@@ -4,7 +4,7 @@ use std::{error::Error, fmt, string::FromUtf8Error, sync::Arc};
4
4
5
5
use http_body_util:: BodyExt as _;
6
6
use hyper:: {
7
- body,
7
+ body:: Body ,
8
8
header:: { self , HeaderValue } ,
9
9
Method , Request , Response , StatusCode ,
10
10
} ;
@@ -15,10 +15,10 @@ use juniper::{
15
15
use serde_json:: error:: Error as SerdeError ;
16
16
use url:: form_urlencoded;
17
17
18
- pub async fn graphql_sync < CtxT , QueryT , MutationT , SubscriptionT , S > (
18
+ pub async fn graphql_sync < CtxT , QueryT , MutationT , SubscriptionT , S , B > (
19
19
root_node : Arc < RootNode < ' static , QueryT , MutationT , SubscriptionT , S > > ,
20
20
context : Arc < CtxT > ,
21
- req : Request < body :: Incoming > ,
21
+ req : Request < B > ,
22
22
) -> Response < String >
23
23
where
24
24
QueryT : GraphQLType < S , Context = CtxT > ,
@@ -29,17 +29,18 @@ where
29
29
SubscriptionT :: TypeInfo : Sync ,
30
30
CtxT : Sync ,
31
31
S : ScalarValue + Send + Sync ,
32
+ B : Body < Error : fmt:: Display > ,
32
33
{
33
34
match parse_req ( req) . await {
34
35
Ok ( req) => execute_request_sync ( root_node, context, req) . await ,
35
36
Err ( resp) => resp,
36
37
}
37
38
}
38
39
39
- pub async fn graphql < CtxT , QueryT , MutationT , SubscriptionT , S > (
40
+ pub async fn graphql < CtxT , QueryT , MutationT , SubscriptionT , S , B > (
40
41
root_node : Arc < RootNode < ' static , QueryT , MutationT , SubscriptionT , S > > ,
41
42
context : Arc < CtxT > ,
42
- req : Request < body :: Incoming > ,
43
+ req : Request < B > ,
43
44
) -> Response < String >
44
45
where
45
46
QueryT : GraphQLTypeAsync < S , Context = CtxT > ,
@@ -50,16 +51,19 @@ where
50
51
SubscriptionT :: TypeInfo : Sync ,
51
52
CtxT : Sync ,
52
53
S : ScalarValue + Send + Sync ,
54
+ B : Body < Error : fmt:: Display > ,
53
55
{
54
56
match parse_req ( req) . await {
55
57
Ok ( req) => execute_request ( root_node, context, req) . await ,
56
58
Err ( resp) => resp,
57
59
}
58
60
}
59
61
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
+ {
63
67
match * req. method ( ) {
64
68
Method :: GET => parse_get_req ( req) ,
65
69
Method :: POST => {
@@ -78,9 +82,11 @@ async fn parse_req<S: ScalarValue>(
78
82
. map_err ( render_error)
79
83
}
80
84
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
+ {
84
90
req. uri ( )
85
91
. query ( )
86
92
. map ( |q| gql_request_from_get ( q) . map ( GraphQLBatchRequest :: Single ) )
@@ -91,9 +97,13 @@ fn parse_get_req<S: ScalarValue>(
91
97
} )
92
98
}
93
99
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
+ {
97
107
let chunk = body
98
108
. collect ( )
99
109
. await
@@ -106,9 +116,13 @@ async fn parse_post_json_req<S: ScalarValue>(
106
116
. map_err ( GraphQLRequestError :: BodyJSONError )
107
117
}
108
118
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
+ {
112
126
let chunk = body
113
127
. collect ( )
114
128
. await
@@ -143,7 +157,10 @@ pub async fn playground(
143
157
resp
144
158
}
145
159
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
+ {
147
164
let mut resp = new_response ( StatusCode :: BAD_REQUEST ) ;
148
165
* resp. body_mut ( ) = err. to_string ( ) ;
149
166
resp
@@ -211,9 +228,12 @@ where
211
228
resp
212
229
}
213
230
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 > >
215
234
where
216
235
S : ScalarValue ,
236
+ B : Body ,
217
237
{
218
238
let mut query = None ;
219
239
let mut operation_name = None ;
@@ -254,7 +274,7 @@ where
254
274
}
255
275
}
256
276
257
- fn invalid_err ( parameter_name : & str ) -> GraphQLRequestError {
277
+ fn invalid_err < B : Body > ( parameter_name : & str ) -> GraphQLRequestError < B > {
258
278
GraphQLRequestError :: Invalid ( format ! (
259
279
"`{parameter_name}` parameter is specified multiple times" ,
260
280
) )
@@ -275,35 +295,57 @@ fn new_html_response(code: StatusCode) -> Response<String> {
275
295
resp
276
296
}
277
297
278
- #[ derive( Debug ) ]
279
- enum GraphQLRequestError {
280
- BodyHyper ( hyper:: Error ) ,
298
+ enum GraphQLRequestError < B : Body > {
299
+ BodyHyper ( B :: Error ) ,
281
300
BodyUtf8 ( FromUtf8Error ) ,
282
301
BodyJSONError ( SerdeError ) ,
283
302
Variables ( SerdeError ) ,
284
303
Invalid ( String ) ,
285
304
}
286
305
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
+ {
288
312
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
289
313
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) ,
295
319
}
296
320
}
297
321
}
298
322
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
+ {
300
342
fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
301
343
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 ,
307
349
}
308
350
}
309
351
}
@@ -314,7 +356,11 @@ mod tests {
314
356
convert:: Infallible , error:: Error , net:: SocketAddr , panic, sync:: Arc , time:: Duration ,
315
357
} ;
316
358
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
+ } ;
318
364
use hyper_util:: rt:: TokioIo ;
319
365
use juniper:: {
320
366
http:: tests as http_tests,
@@ -376,8 +422,7 @@ mod tests {
376
422
}
377
423
}
378
424
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 ) {
381
426
let addr = SocketAddr :: from ( ( [ 127 , 0 , 0 , 1 ] , port) ) ;
382
427
383
428
let db = Arc :: new ( Database :: new ( ) ) ;
@@ -405,7 +450,7 @@ mod tests {
405
450
if let Err ( e) = http1:: Builder :: new ( )
406
451
. serve_connection (
407
452
io,
408
- service_fn ( move |req| {
453
+ service_fn ( move |req : Request < Incoming > | {
409
454
let root_node = root_node. clone ( ) ;
410
455
let db = db. clone ( ) ;
411
456
let matches = {
@@ -419,10 +464,30 @@ mod tests {
419
464
} ;
420
465
async move {
421
466
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
+ }
424
485
} 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
+ }
426
491
}
427
492
} else {
428
493
let mut resp = Response :: new ( String :: new ( ) ) ;
@@ -460,11 +525,21 @@ mod tests {
460
525
461
526
#[ tokio:: test]
462
527
async fn test_hyper_integration ( ) {
463
- run_hyper_integration ( false ) . await
528
+ run_hyper_integration ( 3000 , false , false ) . await
464
529
}
465
530
466
531
#[ tokio:: test]
467
532
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
469
544
}
470
545
}
0 commit comments