@@ -4,7 +4,7 @@ use std::{error::Error, fmt, string::FromUtf8Error, sync::Arc};
44
55use http_body_util:: BodyExt as _;
66use hyper:: {
7- body,
7+ body:: Body ,
88 header:: { self , HeaderValue } ,
99 Method , Request , Response , StatusCode ,
1010} ;
@@ -15,10 +15,10 @@ use juniper::{
1515use serde_json:: error:: Error as SerdeError ;
1616use url:: form_urlencoded;
1717
18- pub async fn graphql_sync < CtxT , QueryT , MutationT , SubscriptionT , S > (
18+ pub async fn graphql_sync < CtxT , QueryT , MutationT , SubscriptionT , S , B > (
1919 root_node : Arc < RootNode < ' static , QueryT , MutationT , SubscriptionT , S > > ,
2020 context : Arc < CtxT > ,
21- req : Request < body :: Incoming > ,
21+ req : Request < B > ,
2222) -> Response < String >
2323where
2424 QueryT : GraphQLType < S , Context = CtxT > ,
@@ -29,17 +29,18 @@ where
2929 SubscriptionT :: TypeInfo : Sync ,
3030 CtxT : Sync ,
3131 S : ScalarValue + Send + Sync ,
32+ B : Body < Error : fmt:: Display > ,
3233{
3334 match parse_req ( req) . await {
3435 Ok ( req) => execute_request_sync ( root_node, context, req) . await ,
3536 Err ( resp) => resp,
3637 }
3738}
3839
39- pub async fn graphql < CtxT , QueryT , MutationT , SubscriptionT , S > (
40+ pub async fn graphql < CtxT , QueryT , MutationT , SubscriptionT , S , B > (
4041 root_node : Arc < RootNode < ' static , QueryT , MutationT , SubscriptionT , S > > ,
4142 context : Arc < CtxT > ,
42- req : Request < body :: Incoming > ,
43+ req : Request < B > ,
4344) -> Response < String >
4445where
4546 QueryT : GraphQLTypeAsync < S , Context = CtxT > ,
@@ -50,16 +51,19 @@ where
5051 SubscriptionT :: TypeInfo : Sync ,
5152 CtxT : Sync ,
5253 S : ScalarValue + Send + Sync ,
54+ B : Body < Error : fmt:: Display > ,
5355{
5456 match parse_req ( req) . await {
5557 Ok ( req) => execute_request ( root_node, context, req) . await ,
5658 Err ( resp) => resp,
5759 }
5860}
5961
60- async fn parse_req < S : ScalarValue > (
61- req : Request < body:: Incoming > ,
62- ) -> Result < GraphQLBatchRequest < S > , Response < String > > {
62+ async fn parse_req < S , B > ( req : Request < B > ) -> Result < GraphQLBatchRequest < S > , Response < String > >
63+ where
64+ S : ScalarValue ,
65+ B : Body < Error : fmt:: Display > ,
66+ {
6367 match * req. method ( ) {
6468 Method :: GET => parse_get_req ( req) ,
6569 Method :: POST => {
@@ -78,9 +82,11 @@ async fn parse_req<S: ScalarValue>(
7882 . map_err ( render_error)
7983}
8084
81- fn parse_get_req < S : ScalarValue > (
82- req : Request < body:: Incoming > ,
83- ) -> Result < GraphQLBatchRequest < S > , GraphQLRequestError > {
85+ fn parse_get_req < S , B > ( req : Request < B > ) -> Result < GraphQLBatchRequest < S > , GraphQLRequestError < B > >
86+ where
87+ S : ScalarValue ,
88+ B : Body ,
89+ {
8490 req. uri ( )
8591 . query ( )
8692 . map ( |q| gql_request_from_get ( q) . map ( GraphQLBatchRequest :: Single ) )
@@ -91,9 +97,13 @@ fn parse_get_req<S: ScalarValue>(
9197 } )
9298}
9399
94- async fn parse_post_json_req < S : ScalarValue > (
95- body : body:: Incoming ,
96- ) -> Result < GraphQLBatchRequest < S > , GraphQLRequestError > {
100+ async fn parse_post_json_req < S , B > (
101+ body : B ,
102+ ) -> Result < GraphQLBatchRequest < S > , GraphQLRequestError < B > >
103+ where
104+ S : ScalarValue ,
105+ B : Body ,
106+ {
97107 let chunk = body
98108 . collect ( )
99109 . await
@@ -106,9 +116,13 @@ async fn parse_post_json_req<S: ScalarValue>(
106116 . map_err ( GraphQLRequestError :: BodyJSONError )
107117}
108118
109- async fn parse_post_graphql_req < S : ScalarValue > (
110- body : body:: Incoming ,
111- ) -> Result < GraphQLBatchRequest < S > , GraphQLRequestError > {
119+ async fn parse_post_graphql_req < S , B > (
120+ body : B ,
121+ ) -> Result < GraphQLBatchRequest < S > , GraphQLRequestError < B > >
122+ where
123+ S : ScalarValue ,
124+ B : Body ,
125+ {
112126 let chunk = body
113127 . collect ( )
114128 . await
@@ -143,7 +157,10 @@ pub async fn playground(
143157 resp
144158}
145159
146- fn render_error ( err : GraphQLRequestError ) -> Response < String > {
160+ fn render_error < B > ( err : GraphQLRequestError < B > ) -> Response < String >
161+ where
162+ B : Body < Error : fmt:: Display > ,
163+ {
147164 let mut resp = new_response ( StatusCode :: BAD_REQUEST ) ;
148165 * resp. body_mut ( ) = err. to_string ( ) ;
149166 resp
@@ -211,9 +228,12 @@ where
211228 resp
212229}
213230
214- fn gql_request_from_get < S > ( input : & str ) -> Result < JuniperGraphQLRequest < S > , GraphQLRequestError >
231+ fn gql_request_from_get < S , B > (
232+ input : & str ,
233+ ) -> Result < JuniperGraphQLRequest < S > , GraphQLRequestError < B > >
215234where
216235 S : ScalarValue ,
236+ B : Body ,
217237{
218238 let mut query = None ;
219239 let mut operation_name = None ;
@@ -254,7 +274,7 @@ where
254274 }
255275}
256276
257- fn invalid_err ( parameter_name : & str ) -> GraphQLRequestError {
277+ fn invalid_err < B : Body > ( parameter_name : & str ) -> GraphQLRequestError < B > {
258278 GraphQLRequestError :: Invalid ( format ! (
259279 "`{parameter_name}` parameter is specified multiple times" ,
260280 ) )
@@ -275,35 +295,57 @@ fn new_html_response(code: StatusCode) -> Response<String> {
275295 resp
276296}
277297
278- #[ derive( Debug ) ]
279- enum GraphQLRequestError {
280- BodyHyper ( hyper:: Error ) ,
298+ enum GraphQLRequestError < B : Body > {
299+ BodyHyper ( B :: Error ) ,
281300 BodyUtf8 ( FromUtf8Error ) ,
282301 BodyJSONError ( SerdeError ) ,
283302 Variables ( SerdeError ) ,
284303 Invalid ( String ) ,
285304}
286305
287- impl fmt:: Display for GraphQLRequestError {
306+ // NOTE: Manual implementation instead of `#[derive(Debug)]` is used to omit imposing unnecessary
307+ // `B: Debug` bound on the implementation.
308+ impl < B > fmt:: Debug for GraphQLRequestError < B >
309+ where
310+ B : Body < Error : fmt:: Debug > ,
311+ {
288312 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
289313 match self {
290- GraphQLRequestError :: BodyHyper ( err ) => fmt:: Display :: fmt ( err , f) ,
291- GraphQLRequestError :: BodyUtf8 ( err ) => fmt:: Display :: fmt ( err , f) ,
292- GraphQLRequestError :: BodyJSONError ( err ) => fmt:: Display :: fmt ( err , f) ,
293- GraphQLRequestError :: Variables ( err ) => fmt:: Display :: fmt ( err , f) ,
294- GraphQLRequestError :: Invalid ( err ) => fmt:: Display :: fmt ( err , f) ,
314+ Self :: BodyHyper ( e ) => fmt:: Debug :: fmt ( e , f) ,
315+ Self :: BodyUtf8 ( e ) => fmt:: Debug :: fmt ( e , f) ,
316+ Self :: BodyJSONError ( e ) => fmt:: Debug :: fmt ( e , f) ,
317+ Self :: Variables ( e ) => fmt:: Debug :: fmt ( e , f) ,
318+ Self :: Invalid ( e ) => fmt:: Debug :: fmt ( e , f) ,
295319 }
296320 }
297321}
298322
299- impl Error for GraphQLRequestError {
323+ impl < B > fmt:: Display for GraphQLRequestError < B >
324+ where
325+ B : Body < Error : fmt:: Display > ,
326+ {
327+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
328+ match self {
329+ Self :: BodyHyper ( e) => fmt:: Display :: fmt ( e, f) ,
330+ Self :: BodyUtf8 ( e) => fmt:: Display :: fmt ( e, f) ,
331+ Self :: BodyJSONError ( e) => fmt:: Display :: fmt ( e, f) ,
332+ Self :: Variables ( e) => fmt:: Display :: fmt ( e, f) ,
333+ Self :: Invalid ( e) => fmt:: Display :: fmt ( e, f) ,
334+ }
335+ }
336+ }
337+
338+ impl < B > Error for GraphQLRequestError < B >
339+ where
340+ B : Body < Error : Error + ' static > ,
341+ {
300342 fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
301343 match self {
302- GraphQLRequestError :: BodyHyper ( err ) => Some ( err ) ,
303- GraphQLRequestError :: BodyUtf8 ( err ) => Some ( err ) ,
304- GraphQLRequestError :: BodyJSONError ( err ) => Some ( err ) ,
305- GraphQLRequestError :: Variables ( err ) => Some ( err ) ,
306- GraphQLRequestError :: Invalid ( _) => None ,
344+ Self :: BodyHyper ( e ) => Some ( e ) ,
345+ Self :: BodyUtf8 ( e ) => Some ( e ) ,
346+ Self :: BodyJSONError ( e ) => Some ( e ) ,
347+ Self :: Variables ( e ) => Some ( e ) ,
348+ Self :: Invalid ( _) => None ,
307349 }
308350 }
309351}
@@ -314,7 +356,11 @@ mod tests {
314356 convert:: Infallible , error:: Error , net:: SocketAddr , panic, sync:: Arc , time:: Duration ,
315357 } ;
316358
317- use hyper:: { server:: conn:: http1, service:: service_fn, Method , Response , StatusCode } ;
359+ use http_body_util:: BodyExt as _;
360+ use hyper:: {
361+ body:: Incoming , server:: conn:: http1, service:: service_fn, Method , Request , Response ,
362+ StatusCode ,
363+ } ;
318364 use hyper_util:: rt:: TokioIo ;
319365 use juniper:: {
320366 http:: tests as http_tests,
@@ -376,8 +422,7 @@ mod tests {
376422 }
377423 }
378424
379- async fn run_hyper_integration ( is_sync : bool ) {
380- let port = if is_sync { 3002 } else { 3001 } ;
425+ async fn run_hyper_integration ( port : u16 , is_sync : bool , is_custom_type : bool ) {
381426 let addr = SocketAddr :: from ( ( [ 127 , 0 , 0 , 1 ] , port) ) ;
382427
383428 let db = Arc :: new ( Database :: new ( ) ) ;
@@ -405,7 +450,7 @@ mod tests {
405450 if let Err ( e) = http1:: Builder :: new ( )
406451 . serve_connection (
407452 io,
408- service_fn ( move |req| {
453+ service_fn ( move |req : Request < Incoming > | {
409454 let root_node = root_node. clone ( ) ;
410455 let db = db. clone ( ) ;
411456 let matches = {
@@ -419,10 +464,30 @@ mod tests {
419464 } ;
420465 async move {
421466 Ok :: < _ , Infallible > ( if matches {
422- if is_sync {
423- super :: graphql_sync ( root_node, db, req) . await
467+ if is_custom_type {
468+ let ( parts, mut body) = req. into_parts ( ) ;
469+ let body = {
470+ let mut buf = String :: new ( ) ;
471+ if let Some ( Ok ( frame) ) = body. frame ( ) . await {
472+ if let Ok ( bytes) = frame. into_data ( ) {
473+ buf = String :: from_utf8_lossy ( & bytes)
474+ . to_string ( ) ;
475+ }
476+ }
477+ buf
478+ } ;
479+ let req = Request :: from_parts ( parts, body) ;
480+ if is_sync {
481+ super :: graphql_sync ( root_node, db, req) . await
482+ } else {
483+ super :: graphql ( root_node, db, req) . await
484+ }
424485 } else {
425- super :: graphql ( root_node, db, req) . await
486+ if is_sync {
487+ super :: graphql_sync ( root_node, db, req) . await
488+ } else {
489+ super :: graphql ( root_node, db, req) . await
490+ }
426491 }
427492 } else {
428493 let mut resp = Response :: new ( String :: new ( ) ) ;
@@ -460,11 +525,21 @@ mod tests {
460525
461526 #[ tokio:: test]
462527 async fn test_hyper_integration ( ) {
463- run_hyper_integration ( false ) . await
528+ run_hyper_integration ( 3000 , false , false ) . await
464529 }
465530
466531 #[ tokio:: test]
467532 async fn test_sync_hyper_integration ( ) {
468- run_hyper_integration ( true ) . await
533+ run_hyper_integration ( 3001 , true , false ) . await
534+ }
535+
536+ #[ tokio:: test]
537+ async fn test_custom_request_hyper_integration ( ) {
538+ run_hyper_integration ( 3002 , false , false ) . await
539+ }
540+
541+ #[ tokio:: test]
542+ async fn test_custom_request_sync_hyper_integration ( ) {
543+ run_hyper_integration ( 3003 , true , true ) . await
469544 }
470545}
0 commit comments