@@ -4,6 +4,8 @@ use std::task::Context;
4
4
use std:: task:: Poll ;
5
5
use std:: time:: Instant ;
6
6
7
+ use graph:: prelude:: serde_json;
8
+ use graph:: prelude:: serde_json:: json;
7
9
use graph:: prelude:: * ;
8
10
use graph:: semver:: VersionReq ;
9
11
use graph:: { components:: server:: query:: GraphQLServerError , data:: query:: QueryTarget } ;
@@ -62,14 +64,17 @@ where
62
64
}
63
65
64
66
async fn index ( self ) -> GraphQLServiceResult {
67
+ let response_obj = json ! ( {
68
+ "message" : "Access deployed subgraphs by deployment ID at \
69
+ /subgraphs/id/<ID> or by name at /subgraphs/name/<NAME>"
70
+ } ) ;
71
+ let response_str = serde_json:: to_string ( & response_obj) . unwrap ( ) ;
72
+
65
73
Ok ( Response :: builder ( )
66
74
. status ( 200 )
67
75
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
68
- . header ( CONTENT_TYPE , "text/plain" )
69
- . body ( Body :: from ( String :: from (
70
- "Access deployed subgraphs by deployment ID at \
71
- /subgraphs/id/<ID> or by name at /subgraphs/name/<NAME>",
72
- ) ) )
76
+ . header ( CONTENT_TYPE , "application/json" )
77
+ . body ( Body :: from ( response_str) )
73
78
. unwrap ( ) )
74
79
}
75
80
79
84
Ok ( Response :: builder ( )
80
85
. status ( 200 )
81
86
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
82
- . header ( CONTENT_TYPE , "text/html" )
87
+ . header ( CONTENT_TYPE , "text/html; charset=utf-8 " )
83
88
. body ( Body :: from ( contents) )
84
89
. unwrap ( ) )
85
90
}
@@ -202,7 +207,7 @@ where
202
207
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
203
208
. header ( ACCESS_CONTROL_ALLOW_HEADERS , "Content-Type, User-Agent" )
204
209
. header ( ACCESS_CONTROL_ALLOW_METHODS , "GET, OPTIONS, POST" )
205
- . header ( CONTENT_TYPE , "text/html" )
210
+ . header ( CONTENT_TYPE , "text/html; charset=utf-8 " )
206
211
. body ( Body :: from ( "" ) )
207
212
. unwrap ( ) )
208
213
}
@@ -220,7 +225,7 @@ where
220
225
. status ( StatusCode :: FOUND )
221
226
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
222
227
. header ( LOCATION , loc_header_val)
223
- . header ( CONTENT_TYPE , "text/plain" )
228
+ . header ( CONTENT_TYPE , "text/plain; charset=utf-8 " )
224
229
. body ( Body :: from ( "Redirecting..." ) )
225
230
. unwrap ( )
226
231
} )
@@ -229,11 +234,16 @@ where
229
234
/// Handles 404s.
230
235
fn handle_not_found ( & self ) -> GraphQLServiceResponse {
231
236
async {
237
+ let response_obj = json ! ( {
238
+ "message" : "Not found"
239
+ } ) ;
240
+ let response_str = serde_json:: to_string ( & response_obj) . unwrap ( ) ;
241
+
232
242
Ok ( Response :: builder ( )
233
- . status ( StatusCode :: NOT_FOUND )
234
- . header ( CONTENT_TYPE , "text/plain " )
243
+ . status ( 200 )
244
+ . header ( CONTENT_TYPE , "application/json " )
235
245
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
236
- . body ( Body :: from ( "Not found" ) )
246
+ . body ( Body :: from ( response_str ) )
237
247
. unwrap ( ) )
238
248
}
239
249
. boxed ( )
@@ -316,30 +326,43 @@ where
316
326
// Instead, we generate a Response with an error code and return Ok
317
327
Box :: pin ( async move {
318
328
let result = service. handle_call ( req) . await ;
329
+
319
330
match result {
320
331
Ok ( response) => Ok ( response) ,
321
- Err ( err @ GraphQLServerError :: ClientError ( _) ) => Ok ( Response :: builder ( )
322
- . status ( 400 )
323
- . header ( CONTENT_TYPE , "text/plain" )
324
- . header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
325
- . body ( Body :: from ( err. to_string ( ) ) )
326
- . unwrap ( ) ) ,
332
+ Err ( err @ GraphQLServerError :: ClientError ( _) ) => {
333
+ let response_obj = json ! ( {
334
+ "error" : err. to_string( )
335
+ } ) ;
336
+ let response_str = serde_json:: to_string ( & response_obj) . unwrap ( ) ;
337
+
338
+ Ok ( Response :: builder ( )
339
+ . status ( 200 )
340
+ . header ( CONTENT_TYPE , "application/json" )
341
+ . header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
342
+ . body ( Body :: from ( response_str) )
343
+ . unwrap ( ) )
344
+ }
327
345
Err ( err @ GraphQLServerError :: QueryError ( _) ) => {
328
346
error ! ( logger, "GraphQLService call failed: {}" , err) ;
329
347
348
+ let response_obj = json ! ( {
349
+ "QueryError" : err. to_string( )
350
+ } ) ;
351
+ let response_str = serde_json:: to_string ( & response_obj) . unwrap ( ) ;
352
+
330
353
Ok ( Response :: builder ( )
331
- . status ( 400 )
332
- . header ( CONTENT_TYPE , "text/plain " )
354
+ . status ( 200 )
355
+ . header ( CONTENT_TYPE , "application/json " )
333
356
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
334
- . body ( Body :: from ( format ! ( "Query error: {}" , err ) ) )
357
+ . body ( Body :: from ( response_str ) )
335
358
. unwrap ( ) )
336
359
}
337
360
Err ( err @ GraphQLServerError :: InternalError ( _) ) => {
338
361
error ! ( logger, "GraphQLService call failed: {}" , err) ;
339
362
340
363
Ok ( Response :: builder ( )
341
364
. status ( 500 )
342
- . header ( CONTENT_TYPE , "text/plain" )
365
+ . header ( CONTENT_TYPE , "text/plain; charset=utf-8 " )
343
366
. header ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" )
344
367
. body ( Body :: from ( format ! ( "Internal server error: {}" , err) ) )
345
368
. unwrap ( ) )
@@ -352,7 +375,9 @@ where
352
375
#[ cfg( test) ]
353
376
mod tests {
354
377
use graph:: data:: value:: Object ;
378
+ use http:: header:: CONTENT_TYPE ;
355
379
use http:: status:: StatusCode ;
380
+ use hyper:: body:: HttpBody ;
356
381
use hyper:: service:: Service ;
357
382
use hyper:: { Body , Method , Request } ;
358
383
@@ -423,6 +448,39 @@ mod tests {
423
448
}
424
449
}
425
450
451
+ #[ tokio:: test]
452
+ async fn querying_not_found_routes_responds_correctly ( ) {
453
+ let logger = Logger :: root ( slog:: Discard , o ! ( ) ) ;
454
+ let graphql_runner = Arc :: new ( TestGraphQlRunner ) ;
455
+
456
+ let node_id = NodeId :: new ( "test" ) . unwrap ( ) ;
457
+ let mut service = GraphQLService :: new ( logger, graphql_runner, 8001 , node_id) ;
458
+
459
+ let request = Request :: builder ( )
460
+ . method ( Method :: GET )
461
+ . header ( CONTENT_TYPE , "text/plain; charset=utf-8" )
462
+ . uri ( "http://localhost:8000/not_found_route" . to_string ( ) )
463
+ . body ( Body :: from ( "{}" ) )
464
+ . unwrap ( ) ;
465
+
466
+ let response =
467
+ futures03:: executor:: block_on ( service. call ( request) ) . expect ( "Should return a response" ) ;
468
+
469
+ let content_type_header = response. status ( ) ;
470
+ assert_eq ! ( content_type_header, StatusCode :: OK ) ;
471
+
472
+ let content_type_header = response. headers ( ) . get ( CONTENT_TYPE ) . unwrap ( ) ;
473
+ assert_eq ! ( content_type_header, "application/json" ) ;
474
+
475
+ let body_bytes = hyper:: body:: to_bytes ( response. into_body ( ) ) . await . unwrap ( ) ;
476
+ let json: serde_json:: Result < serde_json:: Value > =
477
+ serde_json:: from_str ( String :: from_utf8 ( body_bytes. to_vec ( ) ) . unwrap ( ) . as_str ( ) ) ;
478
+
479
+ assert ! ( json. is_ok( ) , "Response body is not valid JSON" ) ;
480
+
481
+ assert_eq ! ( json. unwrap( ) , serde_json:: json!( { "message" : "Not found" } ) ) ;
482
+ }
483
+
426
484
#[ test]
427
485
fn posting_invalid_query_yields_error_response ( ) {
428
486
let logger = Logger :: root ( slog:: Discard , o ! ( ) ) ;
@@ -434,6 +492,7 @@ mod tests {
434
492
435
493
let request = Request :: builder ( )
436
494
. method ( Method :: POST )
495
+ . header ( CONTENT_TYPE , "text/plain; charset=utf-8" )
437
496
. uri ( format ! (
438
497
"http://localhost:8000/subgraphs/id/{}" ,
439
498
subgraph_id
@@ -464,6 +523,7 @@ mod tests {
464
523
465
524
let request = Request :: builder ( )
466
525
. method ( Method :: POST )
526
+ . header ( CONTENT_TYPE , "text/plain; charset=utf-8" )
467
527
. uri ( format ! (
468
528
"http://localhost:8000/subgraphs/id/{}" ,
469
529
subgraph_id
0 commit comments