strawberry-graphql 0.168.2__py3-none-any.whl → 0.170.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,163 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- from io import BytesIO
5
- from typing import TYPE_CHECKING, Any, Dict, Union
6
-
7
- from aiohttp import web
8
- from strawberry.exceptions import MissingQueryError
9
- from strawberry.file_uploads.utils import replace_placeholders_with_files
10
- from strawberry.http import parse_query_params, parse_request_data
11
- from strawberry.schema.exceptions import InvalidOperationTypeError
12
- from strawberry.types.graphql import OperationType
13
- from strawberry.utils.graphiql import get_graphiql_html
14
-
15
- if TYPE_CHECKING:
16
- from typing_extensions import Literal
17
-
18
- from strawberry.http import GraphQLRequestData
19
- from strawberry.schema import BaseSchema
20
-
21
-
22
- class HTTPHandler:
23
- def __init__(
24
- self,
25
- schema: BaseSchema,
26
- graphiql: bool,
27
- allow_queries_via_get: bool,
28
- get_context,
29
- get_root_value,
30
- encode_json,
31
- process_result,
32
- request: web.Request,
33
- ):
34
- self.schema = schema
35
- self.graphiql = graphiql
36
- self.allow_queries_via_get = allow_queries_via_get
37
- self.get_context = get_context
38
- self.get_root_value = get_root_value
39
- self.encode_json = encode_json
40
- self.process_result = process_result
41
- self.request = request
42
-
43
- async def handle(self) -> web.StreamResponse:
44
- if self.request.method == "GET":
45
- return await self.get(self.request)
46
- if self.request.method == "POST":
47
- return await self.post(self.request)
48
- raise web.HTTPMethodNotAllowed(self.request.method, ["GET", "POST"])
49
-
50
- async def get(self, request: web.Request) -> web.StreamResponse:
51
- if request.query:
52
- try:
53
- query_params = {
54
- key: request.query.getone(key) for key in set(request.query.keys())
55
- }
56
- query_data = parse_query_params(query_params)
57
- request_data = parse_request_data(query_data)
58
- except json.JSONDecodeError:
59
- raise web.HTTPBadRequest(reason="Unable to parse request body as JSON")
60
-
61
- return await self.execute_request(
62
- request=request, request_data=request_data, method="GET"
63
- )
64
-
65
- elif self.should_render_graphiql(request):
66
- return self.render_graphiql()
67
- raise web.HTTPNotFound()
68
-
69
- async def post(self, request: web.Request) -> web.StreamResponse:
70
- request_data = await self.get_request_data(request)
71
-
72
- return await self.execute_request(
73
- request=request, request_data=request_data, method="POST"
74
- )
75
-
76
- async def execute_request(
77
- self,
78
- request: web.Request,
79
- request_data: GraphQLRequestData,
80
- method: Union[Literal["GET"], Literal["POST"]],
81
- ) -> web.StreamResponse:
82
- response = web.Response()
83
-
84
- context = await self.get_context(request, response)
85
- root_value = await self.get_root_value(request)
86
-
87
- allowed_operation_types = OperationType.from_http(method)
88
-
89
- if not self.allow_queries_via_get and method == "GET":
90
- allowed_operation_types = allowed_operation_types - {OperationType.QUERY}
91
-
92
- try:
93
- result = await self.schema.execute(
94
- query=request_data.query,
95
- root_value=root_value,
96
- variable_values=request_data.variables,
97
- context_value=context,
98
- operation_name=request_data.operation_name,
99
- allowed_operation_types=allowed_operation_types,
100
- )
101
- except InvalidOperationTypeError as e:
102
- raise web.HTTPBadRequest(
103
- reason=e.as_http_error_reason(method=method)
104
- ) from e
105
- except MissingQueryError:
106
- raise web.HTTPBadRequest(reason="No GraphQL query found in the request")
107
-
108
- response_data = await self.process_result(request, result)
109
-
110
- response.text = self.encode_json(response_data)
111
- response.content_type = "application/json"
112
-
113
- return response
114
-
115
- async def get_request_data(self, request: web.Request) -> GraphQLRequestData:
116
- data = await self.parse_body(request)
117
- return parse_request_data(data)
118
-
119
- async def parse_body(self, request: web.Request) -> dict:
120
- if request.content_type.startswith("multipart/form-data"):
121
- return await self.parse_multipart_body(request)
122
- try:
123
- return await request.json()
124
- except json.JSONDecodeError as e:
125
- raise web.HTTPBadRequest(
126
- reason="Unable to parse request body as JSON"
127
- ) from e
128
-
129
- async def parse_multipart_body(self, request: web.Request) -> dict:
130
- reader = await request.multipart()
131
- operations: Dict[str, Any] = {}
132
- files_map: Dict[str, Any] = {}
133
- files: Dict[str, Any] = {}
134
- try:
135
- async for field in reader:
136
- if field.name == "operations":
137
- operations = (await field.json()) or {}
138
- elif field.name == "map":
139
- files_map = (await field.json()) or {}
140
- elif field.filename:
141
- assert field.name
142
-
143
- files[field.name] = BytesIO(await field.read(decode=False))
144
- except ValueError:
145
- raise web.HTTPBadRequest(reason="Unable to parse the multipart body")
146
- try:
147
- return replace_placeholders_with_files(operations, files_map, files)
148
- except KeyError:
149
- raise web.HTTPBadRequest(reason="File(s) missing in form data")
150
-
151
- def render_graphiql(self) -> web.StreamResponse:
152
- html_string = get_graphiql_html()
153
-
154
- return web.Response(text=html_string, content_type="text/html")
155
-
156
- def should_render_graphiql(self, request: web.Request) -> bool:
157
- if not self.graphiql:
158
- return False
159
-
160
- return any(
161
- supported_header in request.headers.get("Accept", "")
162
- for supported_header in ("text/html", "*/*")
163
- )
@@ -1,214 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, Optional
5
-
6
- from starlette import status
7
- from starlette.requests import Request
8
- from starlette.responses import HTMLResponse, PlainTextResponse, Response
9
-
10
- from strawberry.exceptions import MissingQueryError
11
- from strawberry.file_uploads.utils import replace_placeholders_with_files
12
- from strawberry.http import parse_query_params, parse_request_data
13
- from strawberry.schema.exceptions import InvalidOperationTypeError
14
- from strawberry.types.graphql import OperationType
15
- from strawberry.utils.debug import pretty_print_graphql_operation
16
- from strawberry.utils.graphiql import get_graphiql_html
17
-
18
- if TYPE_CHECKING:
19
- from starlette.types import Receive, Scope, Send
20
-
21
- from strawberry.schema import BaseSchema
22
- from strawberry.types.execution import ExecutionResult
23
-
24
-
25
- class HTTPHandler:
26
- def __init__(
27
- self,
28
- schema: BaseSchema,
29
- graphiql: bool,
30
- allow_queries_via_get: bool,
31
- debug: bool,
32
- get_context,
33
- get_root_value,
34
- process_result,
35
- encode_json,
36
- ):
37
- self.schema = schema
38
- self.graphiql = graphiql
39
- self.allow_queries_via_get = allow_queries_via_get
40
- self.debug = debug
41
- self.get_context = get_context
42
- self.get_root_value = get_root_value
43
- self.process_result = process_result
44
- self.encode_json = encode_json
45
-
46
- async def handle(self, scope: Scope, receive: Receive, send: Send) -> None:
47
- request = Request(scope=scope, receive=receive)
48
- root_value = await self.get_root_value(request)
49
-
50
- sub_response = Response()
51
- sub_response.status_code = None # type: ignore
52
- del sub_response.headers["content-length"]
53
-
54
- context = await self.get_context(request=request, response=sub_response)
55
-
56
- response = await self.get_http_response(
57
- request=request,
58
- execute=self.execute,
59
- process_result=self.process_result,
60
- root_value=root_value,
61
- context=context,
62
- )
63
-
64
- response.headers.raw.extend(sub_response.headers.raw)
65
-
66
- if sub_response.background:
67
- response.background = sub_response.background
68
-
69
- if sub_response.status_code:
70
- response.status_code = sub_response.status_code
71
-
72
- await response(scope, receive, send)
73
-
74
- async def get_http_response(
75
- self,
76
- request: Request,
77
- execute: Callable,
78
- process_result: Callable,
79
- root_value: Optional[Any],
80
- context: Optional[Any],
81
- ) -> Response:
82
- method = request.method
83
-
84
- if method == "GET":
85
- if request.query_params:
86
- try:
87
- data = parse_query_params(request.query_params._dict)
88
- except json.JSONDecodeError:
89
- return PlainTextResponse(
90
- "Unable to parse request body as JSON",
91
- status_code=status.HTTP_400_BAD_REQUEST,
92
- )
93
-
94
- elif self.should_render_graphiql(request):
95
- return self.get_graphiql_response()
96
- else:
97
- return HTMLResponse(status_code=status.HTTP_404_NOT_FOUND)
98
- elif method == "POST":
99
- content_type = request.headers.get("Content-Type", "")
100
- if "application/json" in content_type:
101
- try:
102
- data = await request.json()
103
- except json.JSONDecodeError:
104
- return PlainTextResponse(
105
- "Unable to parse request body as JSON",
106
- status_code=status.HTTP_400_BAD_REQUEST,
107
- )
108
- elif content_type.startswith("multipart/form-data"):
109
- multipart_data = await request.form()
110
- try:
111
- operations_text = multipart_data.get("operations", "{}")
112
- operations = json.loads(operations_text) # type: ignore
113
- files_map = json.loads(multipart_data.get("map", "{}")) # type: ignore # noqa: E501
114
- except json.JSONDecodeError:
115
- return PlainTextResponse(
116
- "Unable to parse request body as JSON",
117
- status_code=status.HTTP_400_BAD_REQUEST,
118
- )
119
-
120
- try:
121
- data = replace_placeholders_with_files(
122
- operations, files_map, multipart_data
123
- )
124
- except KeyError:
125
- return PlainTextResponse(
126
- "File(s) missing in form data",
127
- status_code=status.HTTP_400_BAD_REQUEST,
128
- )
129
- else:
130
- return PlainTextResponse(
131
- "Unsupported Media Type",
132
- status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
133
- )
134
- else:
135
- return PlainTextResponse(
136
- "Method Not Allowed",
137
- status_code=status.HTTP_405_METHOD_NOT_ALLOWED,
138
- )
139
-
140
- try:
141
- request_data = parse_request_data(data)
142
- except json.JSONDecodeError:
143
- return PlainTextResponse(
144
- "Unable to parse request body as JSON",
145
- status_code=status.HTTP_400_BAD_REQUEST,
146
- )
147
-
148
- allowed_operation_types = OperationType.from_http(method)
149
-
150
- if not self.allow_queries_via_get and method == "GET":
151
- allowed_operation_types = allowed_operation_types - {OperationType.QUERY}
152
-
153
- try:
154
- result = await execute(
155
- request_data.query,
156
- variables=request_data.variables,
157
- context=context,
158
- operation_name=request_data.operation_name,
159
- root_value=root_value,
160
- allowed_operation_types=allowed_operation_types,
161
- )
162
- except InvalidOperationTypeError as e:
163
- return PlainTextResponse(
164
- e.as_http_error_reason(method),
165
- status_code=status.HTTP_400_BAD_REQUEST,
166
- )
167
- except MissingQueryError:
168
- return PlainTextResponse(
169
- "No GraphQL query found in the request",
170
- status_code=status.HTTP_400_BAD_REQUEST,
171
- )
172
-
173
- response_data = await process_result(request=request, result=result)
174
-
175
- return Response(
176
- self.encode_json(response_data),
177
- status_code=status.HTTP_200_OK,
178
- media_type="application/json",
179
- )
180
-
181
- def should_render_graphiql(self, request: Request) -> bool:
182
- if not self.graphiql:
183
- return False
184
-
185
- return any(
186
- supported_header in request.headers.get("accept", "")
187
- for supported_header in ("text/html", "*/*")
188
- )
189
-
190
- def get_graphiql_response(self) -> HTMLResponse:
191
- html = get_graphiql_html()
192
-
193
- return HTMLResponse(html)
194
-
195
- async def execute(
196
- self,
197
- query: str,
198
- variables: Optional[Dict[str, Any]] = None,
199
- context: Any = None,
200
- operation_name: Optional[str] = None,
201
- root_value: Any = None,
202
- allowed_operation_types: Optional[Iterable[OperationType]] = None,
203
- ) -> ExecutionResult:
204
- if self.debug:
205
- pretty_print_graphql_operation(operation_name, query, variables)
206
-
207
- return await self.schema.execute(
208
- query,
209
- root_value=root_value,
210
- variable_values=variables,
211
- operation_name=operation_name,
212
- context_value=context,
213
- allowed_operation_types=allowed_operation_types,
214
- )