12
12
from graphql .type .schema import GraphQLSchema
13
13
from graphql .utils .get_operation_ast import get_operation_ast
14
14
15
+ from .render_graphiql import render_graphiql
16
+
15
17
16
18
class HttpError (Exception ):
17
19
def __init__ (self , response , message = None , * args , ** kwargs ):
@@ -23,9 +25,11 @@ def __init__(self, response, message=None, *args, **kwargs):
23
25
class GraphQLView (View ):
24
26
schema = None
25
27
executor = None
26
- execute = None
27
28
root_value = None
29
+ context = None
28
30
pretty = False
31
+ graphiql = False
32
+ graphiql_version = None
29
33
30
34
methods = ['GET' , 'POST' , 'PUT' , 'DELETE' ]
31
35
@@ -36,7 +40,8 @@ def __init__(self, **kwargs):
36
40
setattr (self , key , value )
37
41
38
42
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 )
40
45
41
46
if inner_schema :
42
47
self .schema = inner_schema
@@ -55,21 +60,47 @@ def dispatch_request(self):
55
60
if request .method .lower () not in ('get' , 'post' ):
56
61
raise HttpError (MethodNotAllowed (['GET' , 'POST' ], 'GraphQL only supports GET and POST requests.' ))
57
62
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 = {}
60
78
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 ]
63
81
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 )
66
89
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
+ )
69
100
70
101
return Response (
71
102
status = status_code ,
72
- response = self . json_encode ( request , response ) ,
103
+ response = result ,
73
104
content_type = 'application/json'
74
105
)
75
106
@@ -113,21 +144,18 @@ def parse_body(self, request):
113
144
return {}
114
145
115
146
def execute (self , * args , ** kwargs ):
116
- if self ._execute :
117
- return self ._execute (* args , ** kwargs )
118
147
return execute (self .schema , * args , ** kwargs )
119
148
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 ):
123
150
if not query :
151
+ if show_graphiql :
152
+ return None
124
153
raise HttpError (BadRequest ('Must provide query string.' ))
125
154
126
- source = Source (query , name = 'GraphQL request' )
127
-
128
155
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 )
131
159
if validation_errors :
132
160
return ExecutionResult (
133
161
errors = validation_errors ,
@@ -137,23 +165,39 @@ def execute_graphql_request(self, request):
137
165
return ExecutionResult (errors = [e ], invalid = True )
138
166
139
167
if request .method .lower () == 'get' :
140
- operation_ast = get_operation_ast (document_ast , operation_name )
168
+ operation_ast = get_operation_ast (ast , operation_name )
141
169
if operation_ast and operation_ast .operation != 'query' :
170
+ if show_graphiql :
171
+ return None
142
172
raise HttpError (MethodNotAllowed (
143
173
['POST' ], 'Can only perform a {} operation from a POST request.' .format (operation_ast .operation )
144
174
))
145
175
146
176
try :
147
177
return self .execute (
148
- document_ast ,
178
+ ast ,
149
179
root_value = self .get_root_value (request ),
150
- variable_values = variables ,
180
+ variable_values = variables or {} ,
151
181
operation_name = operation_name ,
152
- context_value = self .get_context (request )
182
+ context_value = self .get_context (request ),
183
+ executor = self .executor
153
184
)
154
185
except Exception as e :
155
186
return ExecutionResult (errors = [e ], invalid = True )
156
187
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
+
157
201
@staticmethod
158
202
def get_graphql_params (request , data ):
159
203
query = request .args .get ('query' ) or data .get ('query' )
0 commit comments