1
1
import json
2
+ from promise import Promise
2
3
3
4
import six
4
5
from flask import Response , request
16
17
17
18
18
19
class HttpError (Exception ):
19
- def __init__ (self , response , message = None , * args , ** kwargs ):
20
- self .response = response
21
- self .message = message = message or response .description
22
- super (HttpError , self ).__init__ (message , * args , ** kwargs )
20
+ def __init__ (self , status_code , message = None , is_graphql_error = False , headers = None ):
21
+ self .status_code = status_code
22
+ self .message = message
23
+ self .is_graphql_error = is_graphql_error
24
+ self .headers = headers
25
+ super (HttpError , self ).__init__ (message )
23
26
24
27
25
28
class GraphQLView (View ):
@@ -42,7 +45,6 @@ def __init__(self, **kwargs):
42
45
if hasattr (self , key ):
43
46
setattr (self , key , value )
44
47
45
- assert not all ((self .graphiql , self .batch )), 'Use either graphiql or batch processing'
46
48
assert isinstance (self .schema , GraphQLSchema ), 'A Schema is required to be provided to GraphQLView.'
47
49
48
50
# noinspection PyUnusedLocal
@@ -70,27 +72,39 @@ def render_graphiql(self, **kwargs):
70
72
def dispatch_request (self ):
71
73
try :
72
74
if request .method .lower () not in ('get' , 'post' ):
73
- raise HttpError (MethodNotAllowed (['GET' , 'POST' ], 'GraphQL only supports GET and POST requests.' ))
75
+ raise HttpError (
76
+ 405 ,
77
+ 'GraphQL only supports GET and POST requests.' ,
78
+ headers = {
79
+ 'Allow' : ['GET, POST' ]
80
+ }
81
+ )
74
82
75
83
data = self .parse_body (request )
76
84
77
85
show_graphiql = self .graphiql and self .can_display_graphiql (data )
78
86
79
- if isinstance (data , list ):
87
+ is_batch = isinstance (data , list )
88
+ if is_batch :
80
89
if not self .batch or show_graphiql :
81
- raise HttpError (BadRequest ('Batch requests are not allowed.' ))
82
-
83
- responses = [self .get_response (request , entry ) for entry in data ]
84
- response , status_codes = zip (* responses )
85
- status_code = max (status_codes )
90
+ raise HttpError (
91
+ 400 ,
92
+ 'Batch requests are not allowed.'
93
+ )
86
94
else :
87
- response , status_code = self .get_response (request , data , show_graphiql )
95
+ data = [data ]
96
+ responses = [self .get_response (request , entry , show_graphiql ) for entry in data ]
97
+ response , status_codes = zip (* responses )
98
+ status_code = max (status_codes )
99
+
100
+ if not is_batch :
101
+ response = response [0 ]
88
102
89
103
pretty = self .pretty or show_graphiql or request .args .get ('pretty' )
90
104
result = self .json_encode (response , pretty )
91
105
92
106
if show_graphiql :
93
- query , variables , operation_name , id = self .get_graphql_params (request , data )
107
+ query , variables , operation_name , id = self .get_graphql_params (request , data [ 0 ] )
94
108
return self .render_graphiql (
95
109
query = query ,
96
110
variables = variables ,
@@ -109,22 +123,23 @@ def dispatch_request(self):
109
123
self .json_encode ({
110
124
'errors' : [self .format_error (e )]
111
125
}),
112
- status = e .response . code ,
113
- headers = { 'Allow' : [ 'GET, POST' ]} ,
126
+ status = e .status_code ,
127
+ headers = e . headers ,
114
128
content_type = 'application/json'
115
129
)
116
130
117
131
def get_response (self , request , data , show_graphiql = False ):
118
132
query , variables , operation_name , id = self .get_graphql_params (request , data )
119
-
120
133
execution_result = self .execute_graphql_request (
121
134
data ,
122
135
query ,
123
136
variables ,
124
137
operation_name ,
125
138
show_graphiql
126
139
)
140
+ return self .format_execution_result (execution_result , id )
127
141
142
+ def format_execution_result (self , execution_result , id ):
128
143
status_code = 200
129
144
if execution_result :
130
145
response = {}
@@ -164,7 +179,10 @@ def parse_body(self, request):
164
179
try :
165
180
return json .loads (request .data .decode ('utf8' ))
166
181
except :
167
- raise HttpError (BadRequest ('POST body sent invalid JSON.' ))
182
+ raise HttpError (
183
+ 400 ,
184
+ 'POST body sent invalid JSON.'
185
+ )
168
186
169
187
elif content_type == 'application/x-www-form-urlencoded' :
170
188
return request .form
@@ -181,7 +199,7 @@ def execute_graphql_request(self, data, query, variables, operation_name, show_g
181
199
if not query :
182
200
if show_graphiql :
183
201
return None
184
- raise HttpError (BadRequest ( 'Must provide query string.' ) )
202
+ raise HttpError (400 , 'Must provide query string.' )
185
203
186
204
try :
187
205
source = Source (query , name = 'GraphQL request' )
@@ -200,9 +218,13 @@ def execute_graphql_request(self, data, query, variables, operation_name, show_g
200
218
if operation_ast and operation_ast .operation != 'query' :
201
219
if show_graphiql :
202
220
return None
203
- raise HttpError (MethodNotAllowed (
204
- ['POST' ], 'Can only perform a {} operation from a POST request.' .format (operation_ast .operation )
205
- ))
221
+ raise HttpError (
222
+ 405 ,
223
+ 'Can only perform a {} operation from a POST request.' .format (operation_ast .operation ),
224
+ headers = {
225
+ 'Allow' : ['POST' ],
226
+ }
227
+ )
206
228
207
229
try :
208
230
return self .execute (
@@ -234,13 +256,13 @@ def request_wants_html(cls, request):
234
256
def get_graphql_params (request , data ):
235
257
query = request .args .get ('query' ) or data .get ('query' )
236
258
variables = request .args .get ('variables' ) or data .get ('variables' )
237
- id = request . args . get ( 'id' ) or data .get ('id' )
259
+ id = data .get ('id' )
238
260
239
261
if variables and isinstance (variables , six .text_type ):
240
262
try :
241
263
variables = json .loads (variables )
242
264
except :
243
- raise HttpError (BadRequest ( 'Variables are invalid JSON.' ) )
265
+ raise HttpError (400 , 'Variables are invalid JSON.' )
244
266
245
267
operation_name = request .args .get ('operationName' ) or data .get ('operationName' )
246
268
0 commit comments