@@ -7,11 +7,19 @@ use iron::status;
7
7
use iron:: method;
8
8
use iron:: url:: Url ;
9
9
10
- use std:: collections:: BTreeMap ;
10
+ use std:: io:: Read ;
11
+ use std:: io:: Error as IoError ;
12
+ use std:: io:: ErrorKind ;
13
+ use std:: collections:: HashMap ;
14
+ use std:: error:: Error ;
15
+ use std:: fmt;
16
+ use std:: boxed:: Box ;
11
17
12
- use rustc_serialize:: json:: { ToJson , Json } ;
18
+ use serde_json;
19
+ use serde_json:: Value as Json ;
20
+ use serde_json:: error:: Error as SerdeError ;
13
21
14
- use :: { InputValue , GraphQLType , RootNode , Variables , execute} ;
22
+ use :: { InputValue , GraphQLType , RootNode , Variables , execute as execute_query } ;
15
23
16
24
/// Handler that executes GraphQL queries in the given schema
17
25
///
@@ -77,59 +85,74 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
77
85
}
78
86
79
87
fn handle_post ( & self , req : & mut Request ) -> IronResult < Response > {
80
- let json_data = itry ! ( Json :: from_reader( & mut req. body) ) ;
81
-
82
- let json_obj = match json_data {
83
- Json :: Object ( o) => o,
84
- _ => return Ok ( Response :: with ( ( status:: BadRequest , "No JSON object was decoded" ) ) ) ,
85
- } ;
86
-
87
- let mut query = None ;
88
- let mut variables = Variables :: new ( ) ;
89
-
90
- for ( k, v) in json_obj {
91
- if k == "query" {
92
- query = v. as_string ( ) . map ( |s| s. to_owned ( ) ) ;
88
+ let mut request_payload = String :: new ( ) ;
89
+ itry ! ( req. body. read_to_string( & mut request_payload) ) ;
90
+ let json_data =
91
+ match serde_json:: from_str :: < Json > ( & * request_payload) {
92
+ Ok ( json) => json,
93
+ Err ( err) => {
94
+ let error = IronError :: new (
95
+ Box :: new ( GraphQlIronError :: Serde ( err) ) ,
96
+ ( status:: BadRequest , "No JSON object was decoded." ) ) ;
97
+ return Err ( error)
98
+ }
99
+ } ;
100
+ match json_data {
101
+ Json :: Object ( json_obj) => {
102
+ let mut query = None ;
103
+ let mut variables = Variables :: new ( ) ;
104
+ for ( k, v) in json_obj {
105
+ if k == "query" {
106
+ query = v. as_str ( ) . map ( |query| query. to_owned ( ) ) ;
107
+ }
108
+ else if k == "variables" {
109
+ variables = InputValue :: from_json ( v) . to_object_value ( )
110
+ . map ( |o| o. into_iter ( ) . map ( |( k, v) | ( k. to_owned ( ) , v. clone ( ) ) ) . collect ( ) )
111
+ . unwrap_or_default ( ) ;
112
+ }
113
+ }
114
+ let query = iexpect ! ( query) ;
115
+ self . execute ( req, & query, & variables)
93
116
}
94
- else if k == "variables" {
95
- variables = InputValue :: from_json ( v) . to_object_value ( )
96
- . map ( |o| o. into_iter ( ) . map ( |( k, v) | ( k. to_owned ( ) , v. clone ( ) ) ) . collect ( ) )
97
- . unwrap_or_default ( ) ;
117
+ _ => {
118
+ let error = IronError :: new (
119
+ Box :: new ( GraphQlIronError :: IO ( IoError :: new ( ErrorKind :: InvalidData ,
120
+ "Was able parse a JSON item but it\
121
+ was not an object as expected.") ) ) ,
122
+ ( status:: BadRequest , "No JSON object was decoded." ) ) ;
123
+ Err ( error)
98
124
}
99
125
}
100
-
101
- let query = iexpect ! ( query) ;
102
-
103
- self . execute ( req, & query, & variables)
104
126
}
105
127
106
128
fn execute ( & self , req : & mut Request , query : & str , variables : & Variables ) -> IronResult < Response > {
107
129
let context = ( self . context_factory ) ( req) ;
108
- let result = execute ( query, None , & self . root_node , variables, & context) ;
109
-
130
+ let result = execute_query ( query, None , & self . root_node , variables, & context) ;
110
131
let content_type = "application/json" . parse :: < Mime > ( ) . unwrap ( ) ;
111
- let mut map = BTreeMap :: new ( ) ;
132
+ let mut map = HashMap :: new ( ) ;
112
133
113
134
match result {
114
135
Ok ( ( result, errors) ) => {
115
- map. insert ( "data" . to_owned ( ) , result. to_json ( ) ) ;
136
+ let response_data = serde_json:: to_value ( result)
137
+ . expect ( "Failed to convert response data to JSON." ) ;
138
+ map. insert ( "data" . to_owned ( ) , response_data) ;
116
139
117
140
if !errors. is_empty ( ) {
118
- map. insert ( "errors" . to_owned ( ) , errors. to_json ( ) ) ;
141
+ let response_data = serde_json:: to_value ( errors)
142
+ . expect ( "Failed to convert the errors to JSON." ) ;
143
+ map. insert ( "errors" . to_owned ( ) , response_data) ;
119
144
}
120
-
121
- let data = Json :: Object ( map) ;
122
- let json = data. pretty ( ) ;
123
-
124
- Ok ( Response :: with ( ( content_type, status:: Ok , json. to_string ( ) ) ) )
145
+ let data = serde_json:: to_value ( map) . expect ( "Failed to convert response to JSON" ) ;
146
+ let json = serde_json:: to_string_pretty ( & data) . expect ( "Failed to convert response to JSON." ) ;
147
+ Ok ( Response :: with ( ( content_type, status:: Ok , json) ) )
125
148
}
126
-
127
149
Err ( err) => {
128
- map. insert ( "errors" . to_owned ( ) , err. to_json ( ) ) ;
129
-
130
- let data = Json :: Object ( map) ;
131
- let json = data. pretty ( ) ;
132
-
150
+ let response_data = serde_json:: to_value ( err)
151
+ . expect ( "Failed to convert error data to JSON." ) ;
152
+ map. insert ( "errors" . to_owned ( ) , response_data) ;
153
+ let data = serde_json:: to_value ( map) . expect ( "Failed to convert response to JSON" ) ;
154
+ let json = serde_json:: to_string_pretty ( & data)
155
+ . expect ( "Failed to convert response to JSON" ) ;
133
156
Ok ( Response :: with ( ( content_type, status:: BadRequest , json. to_string ( ) ) ) )
134
157
}
135
158
}
@@ -236,11 +259,61 @@ impl Handler for GraphiQLHandler {
236
259
}
237
260
}
238
261
262
+ /// A general error allowing the developer to see the underlying issue.
263
+ pub enum GraphQlIronError {
264
+ ///Captures any errors that were caused by Serde.
265
+ Serde ( SerdeError ) ,
266
+ /// Captures any error related the IO.
267
+ IO ( IoError )
268
+ }
269
+
270
+ impl fmt:: Display for GraphQlIronError {
271
+ fn fmt ( & self , mut f : & mut fmt:: Formatter ) -> fmt:: Result {
272
+ match * self {
273
+ GraphQlIronError :: Serde ( ref err) => fmt:: Display :: fmt ( err, & mut f) ,
274
+ GraphQlIronError :: IO ( ref err) => fmt:: Display :: fmt ( err, & mut f) ,
275
+ }
276
+ }
277
+ }
278
+
279
+ impl fmt:: Debug for GraphQlIronError {
280
+ fn fmt ( & self , mut f : & mut fmt:: Formatter ) -> fmt:: Result {
281
+ match * self {
282
+ GraphQlIronError :: Serde ( ref err) => fmt:: Debug :: fmt ( err, & mut f) ,
283
+ GraphQlIronError :: IO ( ref err) => fmt:: Debug :: fmt ( err, & mut f) ,
284
+ }
285
+ }
286
+ }
287
+
288
+ impl Error for GraphQlIronError {
289
+ fn description ( & self ) -> & str {
290
+ match * self {
291
+ GraphQlIronError :: Serde ( ref err) => {
292
+ err. description ( )
293
+ } ,
294
+ GraphQlIronError :: IO ( ref err) => {
295
+ err. description ( )
296
+ }
297
+ }
298
+ }
299
+
300
+ fn cause ( & self ) -> Option < & Error > {
301
+ match * self {
302
+ GraphQlIronError :: Serde ( ref err) => {
303
+ err. cause ( )
304
+ }
305
+ GraphQlIronError :: IO ( ref err) => {
306
+ err. cause ( )
307
+ }
308
+ }
309
+ }
310
+ }
311
+
239
312
240
313
#[ cfg( test) ]
241
314
mod tests {
242
- use rustc_serialize :: json :: Json ;
243
-
315
+ use serde_json :: Value as Json ;
316
+ use serde_json ;
244
317
use iron:: prelude:: * ;
245
318
use iron:: status;
246
319
use iron:: headers;
@@ -267,7 +340,7 @@ mod tests {
267
340
fn unwrap_json_response ( resp : Response ) -> Json {
268
341
let result = response:: extract_body_to_string ( resp) ;
269
342
270
- Json :: from_str ( & result) . expect ( "Could not parse JSON object" )
343
+ serde_json :: from_str :: < Json > ( & result) . expect ( "Could not parse JSON object" )
271
344
}
272
345
273
346
#[ test]
@@ -286,7 +359,7 @@ mod tests {
286
359
287
360
assert_eq ! (
288
361
json,
289
- Json :: from_str( r#"{"data": {"hero": {"name": "R2-D2"}}}"# )
362
+ serde_json :: from_str:: < Json > ( r#"{"data": {"hero": {"name": "R2-D2"}}}"# )
290
363
. expect( "Invalid JSON constant in test" ) ) ;
291
364
}
292
365
@@ -307,7 +380,7 @@ mod tests {
307
380
308
381
assert_eq ! (
309
382
json,
310
- Json :: from_str( r#"{"data": {"hero": {"name": "R2-D2"}}}"# )
383
+ serde_json :: from_str:: < Json > ( r#"{"data": {"hero": {"name": "R2-D2"}}}"# )
311
384
. expect( "Invalid JSON constant in test" ) ) ;
312
385
}
313
386
0 commit comments