9
9
10
10
11
11
import json
12
- from collections import MutableMapping , namedtuple
12
+ from collections import namedtuple
13
13
14
14
import six
15
15
from graphql import get_default_backend
16
16
from graphql .error import format_error as default_format_error
17
17
from graphql .execution import ExecutionResult
18
+ from graphql .type import GraphQLSchema
18
19
19
20
from .error import HttpQueryError
20
21
22
+ try : # pragma: no cover (Python >= 3.3)
23
+ from collections .abc import MutableMapping
24
+ except ImportError : # pragma: no cover (Python < 3.3)
25
+ # noinspection PyUnresolvedReferences,PyProtectedMember
26
+ from collections import MutableMapping
27
+
21
28
# Necessary for static type checking
29
+ # noinspection PyUnreachableCode
22
30
if False : # flake8: noqa
23
- from typing import List , Dict , Optional , Tuple , Any , Union , Callable , Type
24
- from graphql import GraphQLSchema , GraphQLBackend
31
+ from typing import Any , Callable , Dict , List , Optional , Type , Union
32
+ from graphql import GraphQLBackend
25
33
26
34
27
35
__all__ = [
28
36
"run_http_query" ,
29
37
"encode_execution_results" ,
30
38
"load_json_body" ,
31
- "HttpQueryError" ]
39
+ "json_encode" ,
40
+ "json_encode_pretty" ,
41
+ "HttpQueryError" ,
42
+ "RequestParams" ,
43
+ "ServerResults" ,
44
+ "ServerResponse" ,
45
+ ]
46
+
47
+
48
+ # The public data structures
49
+
50
+ RequestParams = namedtuple ("RequestParams" , "query variables operation_name" )
51
+
52
+ ServerResults = namedtuple ("ServerResults" , "results params" )
53
+
54
+ ServerResponse = namedtuple ("ServerResponse" , "body status_code" )
32
55
33
56
34
57
# The public helper functions
@@ -41,7 +64,7 @@ def run_http_query(
41
64
query_data = None , # type: Optional[Dict]
42
65
batch_enabled = False , # type: bool
43
66
catch = False , # type: bool
44
- ** execute_options # type: Dict
67
+ ** execute_options # type: Any
45
68
):
46
69
"""Execute GraphQL coming from an HTTP query against a given schema.
47
70
@@ -55,9 +78,11 @@ def run_http_query(
55
78
All other keyword arguments are passed on to the GraphQL-Core function for
56
79
executing GraphQL queries.
57
80
58
- This functions returns a tuple with the list of ExecutionResults as first item
81
+ Returns a ServerResults tuple with the list of ExecutionResults as first item
59
82
and the list of parameters that have been used for execution as second item.
60
83
"""
84
+ if not isinstance (schema , GraphQLSchema ):
85
+ raise TypeError ("Expected a GraphQL schema, but received {!r}." .format (schema ))
61
86
if request_method not in ("get" , "post" ):
62
87
raise HttpQueryError (
63
88
405 ,
@@ -78,7 +103,7 @@ def run_http_query(
78
103
if not is_batch :
79
104
if not isinstance (data , (dict , MutableMapping )):
80
105
raise HttpQueryError (
81
- 400 , "GraphQL params should be a dict. Received {}." .format (data )
106
+ 400 , "GraphQL params should be a dict. Received {!r }." .format (data )
82
107
)
83
108
data = [data ]
84
109
elif not batch_enabled :
@@ -94,12 +119,12 @@ def run_http_query(
94
119
95
120
all_params = [get_graphql_params (entry , extra_data ) for entry in data ]
96
121
97
- responses = [
122
+ results = [
98
123
get_response (schema , params , catch_exc , allow_only_query , ** execute_options )
99
124
for params in all_params
100
125
]
101
126
102
- return responses , all_params
127
+ return ServerResults ( results , all_params )
103
128
104
129
105
130
def encode_execution_results (
@@ -108,7 +133,7 @@ def encode_execution_results(
108
133
is_batch = False , # type: bool
109
134
encode = None , # type: Callable[[Dict], Any]
110
135
):
111
- # type: (...) -> Tuple[Any, int]
136
+ # type: (...) -> ServerResponse
112
137
"""Serialize the ExecutionResults.
113
138
114
139
This function takes the ExecutionResults that are returned by run_http_query()
@@ -117,18 +142,21 @@ def encode_execution_results(
117
142
the first one will be used. You can also pass a custom function that formats the
118
143
errors in the ExecutionResults, expecting a dictionary as result and another custom
119
144
function that is used to serialize the output.
145
+
146
+ Returns a ServerResponse tuple with the serialized response as the first item and
147
+ a status code of 200 or 400 in case any result was invalid as the second item.
120
148
"""
121
- responses = [
149
+ results = [
122
150
format_execution_result (execution_result , format_error or default_format_error )
123
151
for execution_result in execution_results
124
152
]
125
- result , status_codes = zip (* responses )
153
+ result , status_codes = zip (* results )
126
154
status_code = max (status_codes )
127
155
128
156
if not is_batch :
129
157
result = result [0 ]
130
158
131
- return ( encode or json_encode )(result ), status_code
159
+ return ServerResponse (( encode or json_encode )(result ), status_code )
132
160
133
161
134
162
def load_json_body (data ):
@@ -144,32 +172,46 @@ def load_json_body(data):
144
172
raise HttpQueryError (400 , "POST body sent invalid JSON." )
145
173
146
174
147
- # Some more private helpers
175
+ def json_encode (data ):
176
+ # type: (Union[Dict,List]) -> str
177
+ """Serialize the given data(a dictionary or a list) using JSON.
178
+
179
+ The given data (a dictionary or a list) will be serialized using JSON
180
+ and returned as a string that will be nicely formatted if you set pretty=True.
181
+ """
182
+ return json .dumps (data , separators = ("," , ":" ))
183
+
148
184
149
- GraphQLParams = namedtuple ("GraphQLParams" , "query variables operation_name" )
185
+ def json_encode_pretty (data ):
186
+ # type: (Union[Dict,List]) -> str
187
+ """Serialize the given data using JSON with nice formatting."""
188
+ return json .dumps (data , indent = 2 , separators = ("," , ": " ))
189
+
190
+
191
+ # Some more private helpers
150
192
151
- GraphQLResponse = namedtuple ("GraphQLResponse " , "result status_code" )
193
+ FormattedResult = namedtuple ("FormattedResult " , "result status_code" )
152
194
153
195
154
196
class _NoException (Exception ):
155
197
"""Private exception used when we don't want to catch any real exception."""
156
198
157
199
158
200
def get_graphql_params (data , query_data ):
159
- # type: (Dict, Dict) -> GraphQLParams
201
+ # type: (Dict, Dict) -> RequestParams
160
202
"""Fetch GraphQL query, variables and operation name parameters from given data.
161
203
162
204
You need to pass both the data from the HTTP request body and the HTTP query string.
163
205
Params from the request body will take precedence over those from the query string.
164
206
165
- You will get a GraphQLParams object with these parameters as attributes in return.
207
+ You will get a RequestParams tuple with these parameters in return.
166
208
"""
167
209
query = data .get ("query" ) or query_data .get ("query" )
168
210
variables = data .get ("variables" ) or query_data .get ("variables" )
169
211
# document_id = data.get('documentId')
170
212
operation_name = data .get ("operationName" ) or query_data .get ("operationName" )
171
213
172
- return GraphQLParams (query , load_json_variables (variables ), operation_name )
214
+ return RequestParams (query , load_json_variables (variables ), operation_name )
173
215
174
216
175
217
def load_json_variables (variables ):
@@ -190,12 +232,12 @@ def load_json_variables(variables):
190
232
191
233
def execute_graphql_request (
192
234
schema , # type: GraphQLSchema
193
- params , # type: GraphQLParams
235
+ params , # type: RequestParams
194
236
allow_only_query = False , # type: bool
195
237
backend = None , # type: GraphQLBackend
196
- ** kwargs # type: Dict
238
+ ** kwargs # type: Any
197
239
):
198
- """Execute a GraphQL request and return a ExecutionResult.
240
+ """Execute a GraphQL request and return an ExecutionResult.
199
241
200
242
You need to pass the GraphQL schema and the GraphQLParams that you can get
201
243
with the get_graphql_params() function. If you only want to allow GraphQL query
@@ -235,18 +277,18 @@ def execute_graphql_request(
235
277
236
278
def get_response (
237
279
schema , # type: GraphQLSchema
238
- params , # type: GraphQLParams
280
+ params , # type: RequestParams
239
281
catch_exc , # type: Type[BaseException]
240
282
allow_only_query = False , # type: bool
241
- ** kwargs # type: Dict
283
+ ** kwargs # type: Any
242
284
):
243
285
# type: (...) -> Optional[ExecutionResult]
244
286
"""Get an individual execution result as response, with option to catch errors.
245
287
246
288
This does the same as execute_graphql_request() except that you can catch errors
247
289
that belong to an exception class that you need to pass as a parameter.
248
290
"""
249
-
291
+ # noinspection PyBroadException
250
292
try :
251
293
execution_result = execute_graphql_request (
252
294
schema , params , allow_only_query , ** kwargs
@@ -261,10 +303,10 @@ def format_execution_result(
261
303
execution_result , # type: Optional[ExecutionResult]
262
304
format_error , # type: Optional[Callable[[Exception], Dict]]
263
305
):
264
- # type: (...) -> GraphQLResponse
306
+ # type: (...) -> FormattedResult
265
307
"""Format an execution result into a GraphQLResponse.
266
308
267
- This converts the given execution result into a GraphQLResponse that contains
309
+ This converts the given execution result into a FormattedResult that contains
268
310
the ExecutionResult converted to a dictionary and an appropriate status code.
269
311
"""
270
312
status_code = 200
@@ -276,17 +318,4 @@ def format_execution_result(
276
318
else :
277
319
response = None
278
320
279
- return GraphQLResponse (response , status_code )
280
-
281
-
282
- def json_encode (data , pretty = False ):
283
- # type: (Union[Dict,List], bool) -> str
284
- """Serialize the given data using JSON.
285
-
286
- The given data (a dictionary or a list) will be serialized using JSON
287
- and returned as a string that will be nicely formatted if you set pretty=True.
288
- """
289
- if not pretty :
290
- return json .dumps (data , separators = ("," , ":" ))
291
-
292
- return json .dumps (data , indent = 2 , separators = ("," , ": " ))
321
+ return FormattedResult (response , status_code )
0 commit comments