Skip to content

Commit cd053ed

Browse files
committed
Fixed executor bug. Moved graphiql to be remote-hosted
1 parent 7b7a448 commit cd053ed

File tree

12 files changed

+112
-1384
lines changed

12 files changed

+112
-1384
lines changed

flask_graphql/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from .blueprint import GraphQL
2-
from .graphiqlview import GraphiQLView
32
from .graphqlview import GraphQLView
43

5-
__all__ = ['GraphQL', 'GraphQLView', 'GraphiQLView']
4+
__all__ = ['GraphQL', 'GraphQLView']

flask_graphql/blueprint.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1+
import warnings
2+
13
from flask import Blueprint
24

3-
from .graphiqlview import GraphiQLView
45
from .graphqlview import GraphQLView
56

67

78
class GraphQL(object):
89
def __init__(self, app, schema, **options):
910
self.app = app
11+
warnings.warn('GraphQL Blueprint is now deprecated, please use GraphQLView directly')
1012
self.blueprint = Blueprint('graphql', __name__,
11-
template_folder='templates',
12-
static_url_path='/static/graphql',
13-
static_folder='static/graphql/')
13+
template_folder='templates')
1414

1515
default_query = options.pop('default_query', None)
1616
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, **options))
17-
app.add_url_rule('/graphiql', view_func=GraphiQLView.as_view('graphiql', default_query=default_query))
1817

1918
self.app.register_blueprint(self.blueprint)

flask_graphql/graphiqlview.py

Lines changed: 0 additions & 17 deletions
This file was deleted.

flask_graphql/graphqlview.py

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from graphql.type.schema import GraphQLSchema
1313
from graphql.utils.get_operation_ast import get_operation_ast
1414

15+
from .render_graphiql import render_graphiql
16+
1517

1618
class HttpError(Exception):
1719
def __init__(self, response, message=None, *args, **kwargs):
@@ -23,9 +25,11 @@ def __init__(self, response, message=None, *args, **kwargs):
2325
class GraphQLView(View):
2426
schema = None
2527
executor = None
26-
execute = None
2728
root_value = None
29+
context = None
2830
pretty = False
31+
graphiql = False
32+
graphiql_version = None
2933

3034
methods = ['GET', 'POST', 'PUT', 'DELETE']
3135

@@ -36,7 +40,8 @@ def __init__(self, **kwargs):
3640
setattr(self, key, value)
3741

3842
inner_schema = getattr(self.schema, 'schema', None)
39-
self._execute = getattr(self.schema, 'execute', None)
43+
if not self.executor:
44+
self.executor = getattr(self.schema, 'executor', None)
4045

4146
if inner_schema:
4247
self.schema = inner_schema
@@ -55,21 +60,47 @@ def dispatch_request(self):
5560
if request.method.lower() not in ('get', 'post'):
5661
raise HttpError(MethodNotAllowed(['GET', 'POST'], 'GraphQL only supports GET and POST requests.'))
5762

58-
execution_result = self.execute_graphql_request(request)
59-
response = {}
63+
data = self.parse_body(request)
64+
show_graphiql = self.graphiql and self.can_display_graphiql(data)
65+
66+
query, variables, operation_name = self.get_graphql_params(request, data)
67+
68+
execution_result = self.execute_graphql_request(
69+
data,
70+
query,
71+
variables,
72+
operation_name,
73+
show_graphiql
74+
)
75+
76+
if execution_result:
77+
response = {}
6078

61-
if execution_result.errors:
62-
response['errors'] = [self.format_error(e) for e in execution_result.errors]
79+
if execution_result.errors:
80+
response['errors'] = [self.format_error(e) for e in execution_result.errors]
6381

64-
if execution_result.invalid:
65-
status_code = 400
82+
if execution_result.invalid:
83+
status_code = 400
84+
else:
85+
status_code = 200
86+
response['data'] = execution_result.data
87+
88+
result = self.json_encode(request, response)
6689
else:
67-
status_code = 200
68-
response['data'] = execution_result.data
90+
result = None
91+
92+
if show_graphiql:
93+
return render_graphiql(
94+
graphiql_version=self.graphiql_version,
95+
query=query,
96+
variables=variables,
97+
operation_name=operation_name,
98+
result=result
99+
)
69100

70101
return Response(
71102
status=status_code,
72-
response=self.json_encode(request, response),
103+
response=result,
73104
content_type='application/json'
74105
)
75106

@@ -113,21 +144,18 @@ def parse_body(self, request):
113144
return {}
114145

115146
def execute(self, *args, **kwargs):
116-
if self._execute:
117-
return self._execute(*args, **kwargs)
118147
return execute(self.schema, *args, **kwargs)
119148

120-
def execute_graphql_request(self, request):
121-
query, variables, operation_name = self.get_graphql_params(request, self.parse_body(request))
122-
149+
def execute_graphql_request(self, data, query, variables, operation_name, show_graphiql=False):
123150
if not query:
151+
if show_graphiql:
152+
return None
124153
raise HttpError(BadRequest('Must provide query string.'))
125154

126-
source = Source(query, name='GraphQL request')
127-
128155
try:
129-
document_ast = parse(source)
130-
validation_errors = validate(self.schema, document_ast)
156+
source = Source(query, name='GraphQL request')
157+
ast = parse(source)
158+
validation_errors = validate(self.schema, ast)
131159
if validation_errors:
132160
return ExecutionResult(
133161
errors=validation_errors,
@@ -137,23 +165,39 @@ def execute_graphql_request(self, request):
137165
return ExecutionResult(errors=[e], invalid=True)
138166

139167
if request.method.lower() == 'get':
140-
operation_ast = get_operation_ast(document_ast, operation_name)
168+
operation_ast = get_operation_ast(ast, operation_name)
141169
if operation_ast and operation_ast.operation != 'query':
170+
if show_graphiql:
171+
return None
142172
raise HttpError(MethodNotAllowed(
143173
['POST'], 'Can only perform a {} operation from a POST request.'.format(operation_ast.operation)
144174
))
145175

146176
try:
147177
return self.execute(
148-
document_ast,
178+
ast,
149179
root_value=self.get_root_value(request),
150-
variable_values=variables,
180+
variable_values=variables or {},
151181
operation_name=operation_name,
152-
context_value=self.get_context(request)
182+
context_value=self.get_context(request),
183+
executor=self.executor
153184
)
154185
except Exception as e:
155186
return ExecutionResult(errors=[e], invalid=True)
156187

188+
@classmethod
189+
def can_display_graphiql(cls, data):
190+
raw = 'raw' in request.args or 'raw' in data
191+
return not raw and cls.request_wants_html(request)
192+
193+
@classmethod
194+
def request_wants_html(cls, request):
195+
best = request.accept_mimetypes \
196+
.best_match(['application/json', 'text/html'])
197+
return best == 'text/html' and \
198+
request.accept_mimetypes[best] > \
199+
request.accept_mimetypes['application/json']
200+
157201
@staticmethod
158202
def get_graphql_params(request, data):
159203
query = request.args.get('query') or data.get('query')

flask_graphql/templates/graphiql.html renamed to flask_graphql/render_graphiql.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1+
from flask import render_template_string
2+
3+
4+
GRAPHIQL_VERSION = '0.7.1'
5+
6+
TEMPLATE = '''<!--
7+
The request to this GraphQL server provided the header "Accept: text/html"
8+
and as a result has been presented GraphiQL - an in-browser IDE for
9+
exploring GraphQL.
10+
If you wish to receive JSON, provide the header "Accept: application/json" or
11+
add "&raw" to the end of the URL within a browser.
12+
-->
113
<!DOCTYPE html>
214
<html>
15+
<head>
316
<style>
417
html, body {
518
height: 100%;
@@ -8,13 +21,12 @@
821
width: 100%;
922
}
1023
</style>
11-
<head>
12-
<link rel="stylesheet" href="{{ url_for("graphql.static", filename="graphiql.css") }}" />
13-
<script src="{{ url_for("graphql.static", filename="fetch.min.js") }}"></script>
14-
<script src="{{ url_for("graphql.static", filename="react.min.js") }}"></script>
15-
<script src="{{ url_for("graphql.static", filename="react-dom.min.js") }}"></script>
16-
<script src="{{ url_for("graphql.static", filename="graphiql.min.js") }}"></script>
17-
</head>
24+
<link href="//cdn.jsdelivr.net/graphiql/{{graphiql_version}}/graphiql.css" rel="stylesheet" />
25+
<script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
26+
<script src="//cdn.jsdelivr.net/react/15.0.0/react.min.js"></script>
27+
<script src="//cdn.jsdelivr.net/react/15.0.0/react-dom.min.js"></script>
28+
<script src="//cdn.jsdelivr.net/graphiql/{{graphiql_version}}/graphiql.min.js"></script>
29+
</head>
1830
<body>
1931
<script>
2032
// Collect the URL parameters
@@ -48,7 +60,7 @@
4860
otherParams[k] = parameters[k];
4961
}
5062
}
51-
var fetchURL = "{{ url_for('graphql') }}";
63+
var fetchURL = locationQuery(otherParams);
5264
5365
// Defines a GraphQL fetcher using the fetch API.
5466
function graphQLFetcher(graphQLParams) {
@@ -93,23 +105,26 @@
93105
}
94106
95107
// Render <GraphiQL /> into the body.
96-
React.render(
108+
ReactDOM.render(
97109
React.createElement(GraphiQL, {
98110
fetcher: graphQLFetcher,
99111
onEditQuery: onEditQuery,
100112
onEditVariables: onEditVariables,
101113
onEditOperationName: onEditOperationName,
102-
{%- if default_query %}
103-
defaultQuery: {{ default_query|tojson }},
104-
{%- endif %}
105-
query: null,
106-
response: null,
107-
variables: null,
108-
operationName: null,
114+
query: {{ query|tojson }},
115+
response: {{ result|tojson }},
116+
variables: {{ variables|tojson }},
117+
operationName: {{ operation_name|tojson }},
109118
}),
110119
document.body
111120
);
112121
</script>
113122
</body>
114-
</html>
123+
</html>'''
124+
125+
126+
def render_graphiql(graphiql_version=None, **kwargs):
127+
if not graphiql_version:
128+
graphiql_version = GRAPHIQL_VERSION
115129

130+
return render_template_string(TEMPLATE, graphiql_version=graphiql_version, **kwargs)

flask_graphql/static/graphql/fetch.min.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)