1212from graphql .type .schema import GraphQLSchema
1313from graphql .utils .get_operation_ast import get_operation_ast
1414
15+ from .render_graphiql import render_graphiql
16+
1517
1618class HttpError (Exception ):
1719 def __init__ (self , response , message = None , * args , ** kwargs ):
@@ -23,9 +25,11 @@ def __init__(self, response, message=None, *args, **kwargs):
2325class 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' )
0 commit comments