Skip to content

Commit 05a6077

Browse files
committed
Refactored code using graphql_server
1 parent 182782c commit 05a6077

File tree

2 files changed

+21
-182
lines changed

2 files changed

+21
-182
lines changed

flask_graphql/graphqlview.py

Lines changed: 20 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,14 @@
11
import json
2-
from promise import Promise
3-
from collections import namedtuple
42

5-
import six
63
from flask import Response, request
74
from flask.views import View
85

9-
from graphql import Source, execute, parse, validate
10-
from graphql.error import format_error as format_graphql_error
11-
from graphql.error import GraphQLError
12-
from graphql.execution import ExecutionResult
136
from graphql.type.schema import GraphQLSchema
14-
from graphql.utils.get_operation_ast import get_operation_ast
7+
from graphql_server import run_http_query, HttpQueryError, default_format_error, load_json_body
158

169
from .render_graphiql import render_graphiql
1710

1811

19-
GraphQLParams = namedtuple('GraphQLParams', 'query,variables,operation_name,id')
20-
GraphQLResponse = namedtuple('GraphQLResponse', 'result,status_code')
21-
22-
23-
class HttpQueryError(Exception):
24-
def __init__(self, status_code, message=None, is_graphql_error=False, headers=None):
25-
self.status_code = status_code
26-
self.message = message
27-
self.is_graphql_error = is_graphql_error
28-
self.headers = headers
29-
super(HttpQueryError, self).__init__(message)
30-
31-
3212
class GraphQLView(View):
3313
schema = None
3414
executor = None
@@ -51,22 +31,18 @@ def __init__(self, **kwargs):
5131

5232
assert isinstance(self.schema, GraphQLSchema), 'A Schema is required to be provided to GraphQLView.'
5333

54-
# Flask
5534
# noinspection PyUnusedLocal
5635
def get_root_value(self):
5736
return self.root_value
5837

59-
# Flask
6038
def get_context(self):
6139
if self.context is not None:
6240
return self.context
6341
return request
6442

65-
# Flask
6643
def get_middleware(self):
6744
return self.middleware
6845

69-
# Flask
7046
def get_executor(self):
7147
return self.executor
7248

@@ -82,57 +58,30 @@ def dispatch_request(self):
8258

8359
try:
8460
request_method = request.method.lower()
85-
if request_method not in ('get', 'post'):
86-
raise HttpQueryError(
87-
405,
88-
'GraphQL only supports GET and POST requests.',
89-
headers={
90-
'Allow': ['GET, POST']
91-
}
92-
)
93-
9461
data = self.parse_body()
95-
is_batch = isinstance(data, list)
62+
if isinstance(data, dict):
63+
data = dict(data, **request.args.to_dict())
9664

97-
show_graphiql = not is_batch and self.should_display_graphiql(data)
65+
show_graphiql = request_method == 'get' and self.should_display_graphiql()
9866
catch = HttpQueryError if show_graphiql else None
99-
only_allow_query = request_method == 'get'
100-
101-
if not is_batch:
102-
if not isinstance(data, dict):
103-
raise HttpQueryError(
104-
400,
105-
'GraphQL params should be a dict. Received {}.'.format(data)
106-
)
107-
data = dict(data, **request.args.to_dict())
108-
data = [data]
109-
elif not self.batch:
110-
raise HttpQueryError(
111-
400,
112-
'Batch GraphQL requests are not enabled.'
113-
)
11467

115-
all_params = [self.get_graphql_params(entry) for entry in data]
68+
pretty = self.pretty or show_graphiql or request.args.get('pretty')
11669

117-
responses = [self.get_response(
70+
result, status_code, all_params = run_http_query(
11871
self.schema,
119-
params,
120-
catch,
121-
only_allow_query,
72+
request_method,
73+
data,
74+
batch_enabled=self.batch,
75+
catch=catch,
76+
77+
# Execute options
12278
root_value=self.get_root_value(),
12379
context_value=self.get_context(),
12480
middleware=self.get_middleware(),
12581
executor=self.get_executor(),
126-
) for params in all_params]
127-
128-
response, status_codes = zip(*responses)
129-
status_code = max(status_codes)
130-
131-
if not is_batch:
132-
response = response[0]
82+
)
13383

134-
pretty = self.pretty or show_graphiql or request.args.get('pretty')
135-
result = self.json_encode(response, pretty)
84+
result = self.json_encode(result, pretty)
13685

13786
if show_graphiql:
13887
return self.render_graphiql(
@@ -149,49 +98,13 @@ def dispatch_request(self):
14998
except HttpQueryError as e:
15099
return Response(
151100
self.json_encode({
152-
'errors': [self.format_error(e)]
101+
'errors': [default_format_error(e)]
153102
}),
154103
status=e.status_code,
155104
headers=e.headers,
156105
content_type='application/json'
157106
)
158107

159-
def get_response(self, schema, params, catch=None, only_allow_query=False, **kwargs):
160-
try:
161-
execution_result = self.execute_graphql_request(
162-
schema,
163-
params,
164-
only_allow_query,
165-
**kwargs
166-
)
167-
except catch:
168-
return GraphQLResponse(None, 400)
169-
170-
return self.format_execution_result(execution_result, params.id, self.format_error)
171-
172-
@staticmethod
173-
def format_execution_result(execution_result, id, format_error):
174-
status_code = 200
175-
if execution_result:
176-
response = {}
177-
178-
if execution_result.errors:
179-
response['errors'] = [format_error(e) for e in execution_result.errors]
180-
181-
if execution_result.invalid:
182-
status_code = 400
183-
else:
184-
status_code = 200
185-
response['data'] = execution_result.data
186-
187-
if id:
188-
response['id'] = id
189-
190-
else:
191-
response = None
192-
193-
return GraphQLResponse(response, status_code)
194-
195108
# Flask
196109
# noinspection PyBroadException
197110
def parse_body(self):
@@ -202,61 +115,14 @@ def parse_body(self):
202115
return {'query': request.data.decode()}
203116

204117
elif content_type == 'application/json':
205-
try:
206-
return json.loads(request.data.decode('utf8'))
207-
except:
208-
raise HttpQueryError(
209-
400,
210-
'POST body sent invalid JSON.'
211-
)
212-
213-
elif content_type == 'application/x-www-form-urlencoded':
214-
return request.form.to_dict()
118+
return load_json_body(request.data.decode('utf8'))
215119

216-
elif content_type == 'multipart/form-data':
120+
elif content_type == 'application/x-www-form-urlencoded' \
121+
or content_type == 'multipart/form-data':
217122
return request.form.to_dict()
218123

219124
return {}
220125

221-
@staticmethod
222-
def execute_graphql_request(schema, params, only_allow_query=False, **kwargs):
223-
if not params.query:
224-
raise HttpQueryError(400, 'Must provide query string.')
225-
226-
try:
227-
source = Source(params.query, name='GraphQL request')
228-
ast = parse(source)
229-
validation_errors = validate(schema, ast)
230-
if validation_errors:
231-
return ExecutionResult(
232-
errors=validation_errors,
233-
invalid=True,
234-
)
235-
except Exception as e:
236-
return ExecutionResult(errors=[e], invalid=True)
237-
238-
if only_allow_query:
239-
operation_ast = get_operation_ast(ast, params.operation_name)
240-
if operation_ast and operation_ast.operation != 'query':
241-
raise HttpQueryError(
242-
405,
243-
'Can only perform a {} operation from a POST request.'.format(operation_ast.operation),
244-
headers={
245-
'Allow': ['POST'],
246-
}
247-
)
248-
249-
try:
250-
return execute(
251-
schema,
252-
ast,
253-
operation_name=params.operation_name,
254-
variable_values=params.variables,
255-
**kwargs
256-
)
257-
except Exception as e:
258-
return ExecutionResult(errors=[e], invalid=True)
259-
260126
@staticmethod
261127
def json_encode(data, pretty=False):
262128
if not pretty:
@@ -268,42 +134,15 @@ def json_encode(data, pretty=False):
268134
separators=(',', ': ')
269135
)
270136

271-
# Flask
272-
def should_display_graphiql(self, data):
273-
if not self.graphiql or 'raw' in data:
137+
def should_display_graphiql(self):
138+
if not self.graphiql or 'raw' in request.args:
274139
return False
275140

276141
return self.request_wants_html()
277142

278-
# Flask
279143
def request_wants_html(self):
280144
best = request.accept_mimetypes \
281145
.best_match(['application/json', 'text/html'])
282146
return best == 'text/html' and \
283147
request.accept_mimetypes[best] > \
284148
request.accept_mimetypes['application/json']
285-
286-
@staticmethod
287-
def get_variables(variables):
288-
if variables and isinstance(variables, six.text_type):
289-
try:
290-
return json.loads(variables)
291-
except:
292-
raise HttpQueryError(400, 'Variables are invalid JSON.')
293-
return variables
294-
295-
@classmethod
296-
def get_graphql_params(cls, data):
297-
query = data.get('query')
298-
variables = cls.get_variables(data.get('variables'))
299-
id = data.get('id')
300-
operation_name = data.get('operationName')
301-
302-
return GraphQLParams(query, variables, operation_name, id)
303-
304-
@staticmethod
305-
def format_error(error):
306-
if isinstance(error, GraphQLError):
307-
return format_graphql_error(error)
308-
309-
return {'message': six.text_type(error)}

tests/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from flask import Flask
22
from flask_graphql import GraphQLView
3-
from .schema import Schema
3+
from schema import Schema
44

55

66
def create_app(path='/graphql', **kwargs):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy