1
1
//! Optional handlers for the Iron framework. Requires the `iron-handlers` feature enabled.
2
-
3
2
use iron:: prelude:: * ;
4
3
use iron:: middleware:: Handler ;
5
4
use iron:: mime:: Mime ;
6
5
use iron:: status;
7
6
use iron:: method;
8
- use iron :: url :: Url ;
7
+ use urlencoded :: { UrlEncodedQuery , UrlDecodingError } ;
9
8
10
9
use std:: io:: Read ;
11
10
use std:: io:: Error as IoError ;
12
11
use std:: io:: ErrorKind ;
13
- use std:: collections:: HashMap ;
14
12
use std:: error:: Error ;
15
13
use std:: fmt;
16
14
use std:: boxed:: Box ;
17
15
18
16
use serde_json;
19
- use serde_json:: Value as Json ;
20
17
use serde_json:: error:: Error as SerdeError ;
21
18
22
- use :: { InputValue , GraphQLType , RootNode , Variables , execute as execute_query} ;
19
+ use :: { InputValue , GraphQLType , RootNode , execute} ;
20
+ use super :: serde:: { WrappedGraphQLResult , GraphQlQuery } ;
23
21
24
22
/// Handler that executes GraphQL queries in the given schema
25
23
///
@@ -46,6 +44,53 @@ pub struct GraphiQLHandler {
46
44
graphql_url : String ,
47
45
}
48
46
47
+
48
+ /// Get queries are allowed to repeat the same key more than once.
49
+ fn check_for_repeat_keys ( params : & Vec < String > ) -> Result < ( ) , IronError > {
50
+ if params. len ( ) > 1 {
51
+ let error = IronError :: new (
52
+ Box :: new ( GraphQlIronError :: IO ( IoError :: new ( ErrorKind :: InvalidData ,
53
+ "Was able parse a query string \
54
+ but a duplicate uri key was \
55
+ found.") ) ) ,
56
+ ( status:: BadRequest , "Duplicate uri key was found." ) ) ;
57
+ Err ( error)
58
+ }
59
+ else {
60
+ Ok ( ( ) )
61
+ }
62
+ }
63
+
64
+ fn parse_url_param ( param : Option < Vec < String > > ) -> Result < Option < String > , IronError > {
65
+ if let Some ( values) = param {
66
+ check_for_repeat_keys ( & values) ?;
67
+ Ok ( Some ( values[ 0 ] . to_owned ( ) ) )
68
+ }
69
+ else {
70
+ Ok ( None )
71
+ }
72
+ }
73
+
74
+ fn parse_variable_param ( param : Option < Vec < String > > ) -> Result < Option < InputValue > , IronError > {
75
+ if let Some ( values) = param {
76
+ check_for_repeat_keys ( & values) ?;
77
+ match serde_json:: from_str :: < InputValue > ( values[ 0 ] . as_ref ( ) ) {
78
+ Ok ( input_values) => {
79
+ Ok ( Some ( input_values) )
80
+ }
81
+ Err ( err) => {
82
+ Err ( IronError :: new (
83
+ Box :: new ( GraphQlIronError :: Serde ( err) ) ,
84
+ ( status:: BadRequest , "No JSON object was decoded." ) ) )
85
+ }
86
+ }
87
+ }
88
+ else {
89
+ Ok ( None )
90
+ }
91
+ }
92
+
93
+
49
94
impl < ' a , CtxFactory , Query , Mutation , CtxT >
50
95
GraphQLHandler < ' a , CtxFactory , Query , Mutation , CtxT >
51
96
where CtxFactory : Fn ( & mut Request ) -> CtxT + Send + Sync + ' static ,
@@ -67,96 +112,62 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
67
112
}
68
113
69
114
70
- fn handle_get ( & self , req : & mut Request ) -> IronResult < Response > {
71
- let url: Url = req. url . clone ( ) . into ( ) ;
72
-
73
- let mut query = None ;
74
- let variables = Variables :: new ( ) ;
75
-
76
- for ( k, v) in url. query_pairs ( ) {
77
- if k == "query" {
78
- query = Some ( v. into_owned ( ) ) ;
115
+ fn handle_get ( & self , req : & mut Request ) -> IronResult < GraphQlQuery > {
116
+ match req. get_mut :: < UrlEncodedQuery > ( ) {
117
+ Ok ( ref mut query_string) => {
118
+ let input_query = parse_url_param ( query_string. remove ( "query" ) . to_owned ( ) ) ?;
119
+ if let Some ( query) = input_query {
120
+ let operation_name =
121
+ parse_url_param ( query_string. remove ( "operationName" ) ) ?;
122
+ let input_variables =
123
+ parse_variable_param ( query_string. remove ( "variables" ) ) ?;
124
+ Ok ( GraphQlQuery :: new ( query, operation_name, input_variables) )
125
+ } else {
126
+ Err ( IronError :: new (
127
+ Box :: new ( GraphQlIronError :: IO ( IoError :: new ( ErrorKind :: InvalidData ,
128
+ "No query key was found in \
129
+ the Get request.") ) ) ,
130
+ ( status:: BadRequest , "No query was provided." ) ) )
131
+ }
132
+ }
133
+ Err ( err) => {
134
+ Err ( IronError :: new (
135
+ Box :: new ( GraphQlIronError :: Url ( err) ) ,
136
+ ( status:: BadRequest , "No JSON object was decoded." ) ) )
79
137
}
80
138
}
81
-
82
- let query = iexpect ! ( query) ;
83
-
84
- self . execute ( req, & query, & variables)
85
139
}
86
140
87
- fn handle_post ( & self , req : & mut Request ) -> IronResult < Response > {
141
+ fn handle_post ( & self , req : & mut Request ) -> IronResult < GraphQlQuery > {
88
142
let mut request_payload = String :: new ( ) ;
89
143
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)
116
- }
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)
124
- }
125
- }
144
+ let graphql_query = serde_json:: from_str :: < GraphQlQuery > ( request_payload. as_str ( ) ) . map_err ( |err|{
145
+ IronError :: new (
146
+ Box :: new ( GraphQlIronError :: Serde ( err) ) ,
147
+ ( status:: BadRequest , "No JSON object was decoded." ) )
148
+ } ) ;
149
+ graphql_query
126
150
}
127
151
128
- fn execute ( & self , req : & mut Request , query : & str , variables : & Variables ) -> IronResult < Response > {
129
- let context = ( self . context_factory ) ( req) ;
130
- let result = execute_query ( query, None , & self . root_node , variables, & context) ;
131
- let content_type = "application/json" . parse :: < Mime > ( ) . unwrap ( ) ;
132
- let mut map = HashMap :: new ( ) ;
133
-
134
- match result {
135
- Ok ( ( result, errors) ) => {
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) ;
139
-
140
- if !errors. is_empty ( ) {
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) ;
144
- }
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) ) )
148
- }
149
- Err ( err) => {
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" ) ;
156
- Ok ( Response :: with ( ( content_type, status:: BadRequest , json. to_string ( ) ) ) )
157
- }
158
- }
159
- }
152
+ fn respond ( & self , req : & mut Request , graphql : GraphQlQuery ) -> IronResult < Response > {
153
+ let context = ( self . context_factory ) ( req) ;
154
+ let variables = graphql. variables ( ) ;
155
+ let result = execute ( graphql. query ( ) ,
156
+ graphql. operation_name ( ) ,
157
+ & self . root_node ,
158
+ & variables,
159
+ & context) ;
160
+ let content_type = "application/json" . parse :: < Mime > ( ) . unwrap ( ) ;
161
+ if result. is_ok ( ) {
162
+ let response = WrappedGraphQLResult :: new ( result) ;
163
+ let json = serde_json:: to_string_pretty ( & response) . unwrap ( ) ;
164
+ Ok ( Response :: with ( ( content_type, status:: Ok , json) ) )
165
+ } else {
166
+ let response = WrappedGraphQLResult :: new ( result) ;
167
+ let json = serde_json:: to_string_pretty ( & response) . unwrap ( ) ;
168
+ Ok ( Response :: with ( ( content_type, status:: BadRequest , json) ) )
169
+ }
170
+ }
160
171
}
161
172
162
173
impl GraphiQLHandler {
@@ -179,10 +190,16 @@ impl<'a, CtxFactory, Query, Mutation, CtxT>
179
190
Query : GraphQLType < Context =CtxT > + Send + Sync + ' static ,
180
191
Mutation : GraphQLType < Context =CtxT > + Send + Sync + ' static , ' a : ' static ,
181
192
{
182
- fn handle ( & self , req : & mut Request ) -> IronResult < Response > {
193
+ fn handle ( & self , mut req : & mut Request ) -> IronResult < Response > {
183
194
match req. method {
184
- method:: Get => self . handle_get ( req) ,
185
- method:: Post => self . handle_post ( req) ,
195
+ method:: Get => {
196
+ let graphql_query = self . handle_get ( & mut req) ?;
197
+ self . respond ( & mut req, graphql_query)
198
+ }
199
+ method:: Post => {
200
+ let graphql_query = self . handle_post ( & mut req) ?;
201
+ self . respond ( & mut req, graphql_query)
202
+ } ,
186
203
_ => Ok ( Response :: with ( ( status:: MethodNotAllowed ) ) )
187
204
}
188
205
}
@@ -202,7 +219,6 @@ impl Handler for GraphiQLHandler {
202
219
}
203
220
</style>
204
221
"# ;
205
-
206
222
let fetcher_source = r#"
207
223
<script>
208
224
function graphQLFetcher(params) {
@@ -260,27 +276,22 @@ impl Handler for GraphiQLHandler {
260
276
}
261
277
262
278
/// A general error allowing the developer to see the underlying issue.
279
+ #[ derive( Debug ) ]
263
280
pub enum GraphQlIronError {
264
281
///Captures any errors that were caused by Serde.
265
282
Serde ( SerdeError ) ,
266
283
/// Captures any error related the IO.
267
- IO ( IoError )
284
+ IO ( IoError ) ,
285
+ /// Captures any error related to Url Decoding,
286
+ Url ( UrlDecodingError )
268
287
}
269
288
270
289
impl fmt:: Display for GraphQlIronError {
271
290
fn fmt ( & self , mut f : & mut fmt:: Formatter ) -> fmt:: Result {
272
291
match * self {
273
292
GraphQlIronError :: Serde ( ref err) => fmt:: Display :: fmt ( err, & mut f) ,
274
293
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) ,
294
+ GraphQlIronError :: Url ( ref err) => fmt:: Display :: fmt ( err, & mut f) ,
284
295
}
285
296
}
286
297
}
@@ -294,6 +305,9 @@ impl Error for GraphQlIronError {
294
305
GraphQlIronError :: IO ( ref err) => {
295
306
err. description ( )
296
307
}
308
+ GraphQlIronError :: Url ( ref err) => {
309
+ err. description ( )
310
+ }
297
311
}
298
312
}
299
313
@@ -305,6 +319,9 @@ impl Error for GraphQlIronError {
305
319
GraphQlIronError :: IO ( ref err) => {
306
320
err. cause ( )
307
321
}
322
+ GraphQlIronError :: Url ( ref err) => {
323
+ err. cause ( )
324
+ }
308
325
}
309
326
}
310
327
}
@@ -363,6 +380,73 @@ mod tests {
363
380
. expect( "Invalid JSON constant in test" ) ) ;
364
381
}
365
382
383
+ #[ test]
384
+ fn test_encoded_get ( ) {
385
+ let response = request:: get (
386
+ "http://localhost:3000/?query=query%20{%20%20%20human(id:%20\" 1000\" )%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}" ,
387
+ Headers :: new ( ) ,
388
+ & make_handler ( ) )
389
+ . expect ( "Unexpected IronError" ) ;
390
+
391
+ assert_eq ! ( response. status, Some ( status:: Ok ) ) ;
392
+ assert_eq ! ( response. headers. get:: <headers:: ContentType >( ) ,
393
+ Some ( & headers:: ContentType :: json( ) ) ) ;
394
+
395
+ let json = unwrap_json_response ( response) ;
396
+
397
+ assert_eq ! (
398
+ json,
399
+ serde_json:: from_str:: <Json >( r#"{
400
+ "data": {
401
+ "human": {
402
+ "appearsIn": [
403
+ "NEW_HOPE",
404
+ "EMPIRE",
405
+ "JEDI"
406
+ ],
407
+ "homePlanet": "Tatooine",
408
+ "name": "Luke Skywalker",
409
+ "id": "1000"
410
+ }
411
+ }
412
+ }"# )
413
+ . expect( "Invalid JSON constant in test" ) ) ;
414
+ }
415
+
416
+ #[ test]
417
+ fn test_get_with_variables ( ) {
418
+ let response = request:: get (
419
+ "http://localhost:3000/?query=query($id:%20String!)%20{%20%20%20human(id:%20$id)%20{%20%20%20%20%20id,%20%20%20%20%20name,%20%20%20%20%20appearsIn,%20%20%20%20%20homePlanet%20%20%20}%20}&variables={%20%20%20\" id\" :%20%20\" 1000\" %20}" ,
420
+ Headers :: new ( ) ,
421
+ & make_handler ( ) )
422
+ . expect ( "Unexpected IronError" ) ;
423
+
424
+ assert_eq ! ( response. status, Some ( status:: Ok ) ) ;
425
+ assert_eq ! ( response. headers. get:: <headers:: ContentType >( ) ,
426
+ Some ( & headers:: ContentType :: json( ) ) ) ;
427
+
428
+ let json = unwrap_json_response ( response) ;
429
+
430
+ assert_eq ! (
431
+ json,
432
+ serde_json:: from_str:: <Json >( r#"{
433
+ "data": {
434
+ "human": {
435
+ "appearsIn": [
436
+ "NEW_HOPE",
437
+ "EMPIRE",
438
+ "JEDI"
439
+ ],
440
+ "homePlanet": "Tatooine",
441
+ "name": "Luke Skywalker",
442
+ "id": "1000"
443
+ }
444
+ }
445
+ }"# )
446
+ . expect( "Invalid JSON constant in test" ) ) ;
447
+ }
448
+
449
+
366
450
#[ test]
367
451
fn test_simple_post ( ) {
368
452
let response = request:: post (
0 commit comments