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.
- strawberry/aiohttp/handlers/__init__.py +1 -2
- strawberry/aiohttp/views.py +109 -47
- strawberry/asgi/__init__.py +118 -29
- strawberry/asgi/handlers/__init__.py +1 -2
- strawberry/chalice/views.py +81 -158
- strawberry/cli/debug_server.py +2 -1
- strawberry/django/views.py +138 -200
- strawberry/fastapi/router.py +101 -164
- strawberry/file_uploads/utils.py +2 -2
- strawberry/flask/views.py +117 -178
- strawberry/http/async_base_view.py +215 -0
- strawberry/http/base.py +63 -0
- strawberry/http/exceptions.py +4 -0
- strawberry/http/sync_base_view.py +210 -0
- strawberry/http/temporal_response.py +3 -1
- strawberry/http/types.py +13 -0
- strawberry/http/typevars.py +7 -0
- strawberry/sanic/utils.py +9 -2
- strawberry/sanic/views.py +86 -136
- strawberry/schema/name_converter.py +4 -1
- strawberry/schema/schema_converter.py +6 -1
- strawberry/starlite/controller.py +119 -177
- strawberry/types/graphql.py +5 -2
- {strawberry_graphql-0.168.2.dist-info → strawberry_graphql-0.170.0.dist-info}/METADATA +1 -1
- {strawberry_graphql-0.168.2.dist-info → strawberry_graphql-0.170.0.dist-info}/RECORD +28 -24
- strawberry/aiohttp/handlers/http_handler.py +0 -163
- strawberry/asgi/handlers/http_handler.py +0 -214
- {strawberry_graphql-0.168.2.dist-info → strawberry_graphql-0.170.0.dist-info}/LICENSE +0 -0
- {strawberry_graphql-0.168.2.dist-info → strawberry_graphql-0.170.0.dist-info}/WHEEL +0 -0
- {strawberry_graphql-0.168.2.dist-info → strawberry_graphql-0.170.0.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,5 @@ from strawberry.aiohttp.handlers.graphql_transport_ws_handler import (
|
|
2
2
|
GraphQLTransportWSHandler,
|
3
3
|
)
|
4
4
|
from strawberry.aiohttp.handlers.graphql_ws_handler import GraphQLWSHandler
|
5
|
-
from strawberry.aiohttp.handlers.http_handler import HTTPHandler
|
6
5
|
|
7
|
-
__all__ = ["GraphQLTransportWSHandler", "GraphQLWSHandler"
|
6
|
+
__all__ = ["GraphQLTransportWSHandler", "GraphQLWSHandler"]
|
strawberry/aiohttp/views.py
CHANGED
@@ -1,33 +1,89 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import asyncio
|
4
|
-
import json
|
5
4
|
from datetime import timedelta
|
6
|
-
from
|
5
|
+
from io import BytesIO
|
6
|
+
from typing import (
|
7
|
+
TYPE_CHECKING,
|
8
|
+
Any,
|
9
|
+
Dict,
|
10
|
+
Iterable,
|
11
|
+
Mapping,
|
12
|
+
Optional,
|
13
|
+
cast,
|
14
|
+
)
|
7
15
|
|
8
16
|
from aiohttp import web
|
9
17
|
from strawberry.aiohttp.handlers import (
|
10
18
|
GraphQLTransportWSHandler,
|
11
19
|
GraphQLWSHandler,
|
12
|
-
HTTPHandler,
|
13
20
|
)
|
14
|
-
from strawberry.http import
|
21
|
+
from strawberry.http.async_base_view import AsyncBaseHTTPView, AsyncHTTPRequestAdapter
|
22
|
+
from strawberry.http.exceptions import HTTPException
|
23
|
+
from strawberry.http.types import FormData, HTTPMethod, QueryParams
|
24
|
+
from strawberry.http.typevars import (
|
25
|
+
Context,
|
26
|
+
RootValue,
|
27
|
+
)
|
15
28
|
from strawberry.subscriptions import GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL
|
29
|
+
from strawberry.utils.graphiql import get_graphiql_html
|
16
30
|
|
17
31
|
if TYPE_CHECKING:
|
18
32
|
from strawberry.http import GraphQLHTTPResponse
|
19
33
|
from strawberry.schema import BaseSchema
|
20
|
-
from strawberry.types import ExecutionResult
|
21
34
|
|
22
35
|
|
23
|
-
class
|
36
|
+
class AioHTTPRequestAdapter(AsyncHTTPRequestAdapter):
|
37
|
+
def __init__(self, request: web.Request):
|
38
|
+
self.request = request
|
39
|
+
|
40
|
+
@property
|
41
|
+
def query_params(self) -> QueryParams:
|
42
|
+
return self.request.query.copy()
|
43
|
+
|
44
|
+
async def get_body(self) -> str:
|
45
|
+
return (await self.request.content.read()).decode()
|
46
|
+
|
47
|
+
@property
|
48
|
+
def method(self) -> HTTPMethod:
|
49
|
+
return cast(HTTPMethod, self.request.method.upper())
|
50
|
+
|
51
|
+
@property
|
52
|
+
def headers(self) -> Mapping[str, str]:
|
53
|
+
return self.request.headers
|
54
|
+
|
55
|
+
async def get_form_data(self) -> FormData:
|
56
|
+
reader = await self.request.multipart()
|
57
|
+
|
58
|
+
data: Dict[str, Any] = {}
|
59
|
+
files: Dict[str, Any] = {}
|
60
|
+
|
61
|
+
async for field in reader:
|
62
|
+
assert field.name
|
63
|
+
|
64
|
+
if field.filename:
|
65
|
+
files[field.name] = BytesIO(await field.read(decode=False))
|
66
|
+
else:
|
67
|
+
data[field.name] = await field.text()
|
68
|
+
|
69
|
+
return FormData(files=files, form=data)
|
70
|
+
|
71
|
+
@property
|
72
|
+
def content_type(self) -> Optional[str]:
|
73
|
+
return self.request.content_type
|
74
|
+
|
75
|
+
|
76
|
+
class GraphQLView(
|
77
|
+
AsyncBaseHTTPView[web.Request, web.Response, web.Response, Context, RootValue]
|
78
|
+
):
|
24
79
|
# Mark the view as coroutine so that AIOHTTP does not confuse it with a deprecated
|
25
80
|
# bare handler function.
|
26
81
|
_is_coroutine = asyncio.coroutines._is_coroutine # type: ignore[attr-defined]
|
27
82
|
|
28
83
|
graphql_transport_ws_handler_class = GraphQLTransportWSHandler
|
29
84
|
graphql_ws_handler_class = GraphQLWSHandler
|
30
|
-
|
85
|
+
allow_queries_via_get = True
|
86
|
+
request_adapter_class = AioHTTPRequestAdapter
|
31
87
|
|
32
88
|
def __init__(
|
33
89
|
self,
|
@@ -52,58 +108,64 @@ class GraphQLView:
|
|
52
108
|
self.subscription_protocols = subscription_protocols
|
53
109
|
self.connection_init_wait_timeout = connection_init_wait_timeout
|
54
110
|
|
111
|
+
def render_graphiql(self, request: web.Request) -> web.Response:
|
112
|
+
# TODO: get_graphiql_html should be on self
|
113
|
+
html_string = get_graphiql_html()
|
114
|
+
|
115
|
+
return web.Response(text=html_string, content_type="text/html")
|
116
|
+
|
117
|
+
async def get_sub_response(self, request: web.Request) -> web.Response:
|
118
|
+
return web.Response()
|
119
|
+
|
55
120
|
async def __call__(self, request: web.Request) -> web.StreamResponse:
|
56
121
|
ws = web.WebSocketResponse(protocols=self.subscription_protocols)
|
57
122
|
ws_test = ws.can_prepare(request)
|
58
123
|
|
59
|
-
if ws_test.ok:
|
60
|
-
|
61
|
-
return await self.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
else:
|
80
|
-
await ws.prepare(request)
|
81
|
-
await ws.close(code=4406, message=b"Subprotocol not acceptable")
|
82
|
-
return ws
|
83
|
-
else:
|
84
|
-
return await self.http_handler_class(
|
124
|
+
if not ws_test.ok:
|
125
|
+
try:
|
126
|
+
return await self.run(request=request)
|
127
|
+
except HTTPException as e:
|
128
|
+
return web.Response(
|
129
|
+
body=e.reason,
|
130
|
+
status=e.status_code,
|
131
|
+
)
|
132
|
+
|
133
|
+
if ws_test.protocol == GRAPHQL_TRANSPORT_WS_PROTOCOL:
|
134
|
+
return await self.graphql_transport_ws_handler_class(
|
135
|
+
schema=self.schema,
|
136
|
+
debug=self.debug,
|
137
|
+
connection_init_wait_timeout=self.connection_init_wait_timeout,
|
138
|
+
get_context=self.get_context, # type: ignore
|
139
|
+
get_root_value=self.get_root_value,
|
140
|
+
request=request,
|
141
|
+
).handle()
|
142
|
+
elif ws_test.protocol == GRAPHQL_WS_PROTOCOL:
|
143
|
+
return await self.graphql_ws_handler_class(
|
85
144
|
schema=self.schema,
|
86
|
-
|
87
|
-
|
145
|
+
debug=self.debug,
|
146
|
+
keep_alive=self.keep_alive,
|
147
|
+
keep_alive_interval=self.keep_alive_interval,
|
88
148
|
get_context=self.get_context,
|
89
149
|
get_root_value=self.get_root_value,
|
90
|
-
encode_json=self.encode_json,
|
91
|
-
process_result=self.process_result,
|
92
150
|
request=request,
|
93
151
|
).handle()
|
152
|
+
else:
|
153
|
+
await ws.prepare(request)
|
154
|
+
await ws.close(code=4406, message=b"Subprotocol not acceptable")
|
155
|
+
return ws
|
94
156
|
|
95
|
-
async def get_root_value(self, request: web.Request) ->
|
157
|
+
async def get_root_value(self, request: web.Request) -> Optional[RootValue]:
|
96
158
|
return None
|
97
159
|
|
98
160
|
async def get_context(
|
99
|
-
self, request: web.Request, response: web.
|
100
|
-
) ->
|
101
|
-
return {"request": request, "response": response}
|
161
|
+
self, request: web.Request, response: web.Response
|
162
|
+
) -> Context:
|
163
|
+
return {"request": request, "response": response} # type: ignore
|
102
164
|
|
103
|
-
|
104
|
-
self,
|
105
|
-
) ->
|
106
|
-
|
165
|
+
def create_response(
|
166
|
+
self, response_data: GraphQLHTTPResponse, sub_response: web.Response
|
167
|
+
) -> web.Response:
|
168
|
+
sub_response.text = self.encode_json(response_data)
|
169
|
+
sub_response.content_type = "application/json"
|
107
170
|
|
108
|
-
|
109
|
-
return json.dumps(response_data)
|
171
|
+
return sub_response
|
strawberry/asgi/__init__.py
CHANGED
@@ -1,33 +1,87 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import json
|
4
3
|
from datetime import timedelta
|
5
|
-
from typing import
|
4
|
+
from typing import (
|
5
|
+
TYPE_CHECKING,
|
6
|
+
Any,
|
7
|
+
Mapping,
|
8
|
+
Optional,
|
9
|
+
Sequence,
|
10
|
+
Union,
|
11
|
+
cast,
|
12
|
+
)
|
6
13
|
|
14
|
+
from starlette import status
|
15
|
+
from starlette.requests import Request
|
16
|
+
from starlette.responses import HTMLResponse, PlainTextResponse, Response
|
7
17
|
from starlette.websockets import WebSocket
|
8
18
|
|
9
19
|
from strawberry.asgi.handlers import (
|
10
20
|
GraphQLTransportWSHandler,
|
11
21
|
GraphQLWSHandler,
|
12
|
-
HTTPHandler,
|
13
22
|
)
|
14
|
-
from strawberry.http import
|
23
|
+
from strawberry.http.async_base_view import AsyncBaseHTTPView, AsyncHTTPRequestAdapter
|
24
|
+
from strawberry.http.exceptions import HTTPException
|
25
|
+
from strawberry.http.types import FormData, HTTPMethod, QueryParams
|
26
|
+
from strawberry.http.typevars import (
|
27
|
+
Context,
|
28
|
+
RootValue,
|
29
|
+
)
|
15
30
|
from strawberry.subscriptions import GRAPHQL_TRANSPORT_WS_PROTOCOL, GRAPHQL_WS_PROTOCOL
|
31
|
+
from strawberry.utils.graphiql import get_graphiql_html
|
16
32
|
|
17
33
|
if TYPE_CHECKING:
|
18
|
-
from starlette.requests import Request
|
19
|
-
from starlette.responses import Response
|
20
34
|
from starlette.types import Receive, Scope, Send
|
21
35
|
|
22
36
|
from strawberry.http import GraphQLHTTPResponse
|
23
37
|
from strawberry.schema import BaseSchema
|
24
|
-
from strawberry.types import ExecutionResult
|
25
38
|
|
26
39
|
|
27
|
-
class
|
40
|
+
class ASGIRequestAdapter(AsyncHTTPRequestAdapter):
|
41
|
+
def __init__(self, request: Request) -> None:
|
42
|
+
self.request = request
|
43
|
+
|
44
|
+
@property
|
45
|
+
def query_params(self) -> QueryParams:
|
46
|
+
return dict(self.request.query_params)
|
47
|
+
|
48
|
+
@property
|
49
|
+
def method(self) -> HTTPMethod:
|
50
|
+
return cast(HTTPMethod, self.request.method.upper())
|
51
|
+
|
52
|
+
@property
|
53
|
+
def headers(self) -> Mapping[str, str]:
|
54
|
+
return self.request.headers
|
55
|
+
|
56
|
+
@property
|
57
|
+
def content_type(self) -> Optional[str]:
|
58
|
+
return self.request.headers.get("content-type")
|
59
|
+
|
60
|
+
async def get_body(self) -> bytes:
|
61
|
+
return await self.request.body()
|
62
|
+
|
63
|
+
async def get_form_data(self) -> FormData:
|
64
|
+
multipart_data = await self.request.form()
|
65
|
+
|
66
|
+
return FormData(
|
67
|
+
files=multipart_data,
|
68
|
+
form=multipart_data,
|
69
|
+
)
|
70
|
+
|
71
|
+
|
72
|
+
class GraphQL(
|
73
|
+
AsyncBaseHTTPView[
|
74
|
+
Union[Request, WebSocket],
|
75
|
+
Response,
|
76
|
+
Response,
|
77
|
+
Context,
|
78
|
+
RootValue,
|
79
|
+
]
|
80
|
+
):
|
28
81
|
graphql_transport_ws_handler_class = GraphQLTransportWSHandler
|
29
82
|
graphql_ws_handler_class = GraphQLWSHandler
|
30
|
-
|
83
|
+
allow_queries_via_get = True
|
84
|
+
request_adapter_class = ASGIRequestAdapter # pyright: ignore
|
31
85
|
|
32
86
|
def __init__(
|
33
87
|
self,
|
@@ -37,7 +91,10 @@ class GraphQL:
|
|
37
91
|
keep_alive: bool = False,
|
38
92
|
keep_alive_interval: float = 1,
|
39
93
|
debug: bool = False,
|
40
|
-
subscription_protocols=(
|
94
|
+
subscription_protocols: Sequence[str] = (
|
95
|
+
GRAPHQL_TRANSPORT_WS_PROTOCOL,
|
96
|
+
GRAPHQL_WS_PROTOCOL,
|
97
|
+
),
|
41
98
|
connection_init_wait_timeout: timedelta = timedelta(minutes=1),
|
42
99
|
) -> None:
|
43
100
|
self.schema = schema
|
@@ -51,16 +108,7 @@ class GraphQL:
|
|
51
108
|
|
52
109
|
async def __call__(self, scope: Scope, receive: Receive, send: Send):
|
53
110
|
if scope["type"] == "http":
|
54
|
-
await self.
|
55
|
-
schema=self.schema,
|
56
|
-
graphiql=self.graphiql,
|
57
|
-
allow_queries_via_get=self.allow_queries_via_get,
|
58
|
-
debug=self.debug,
|
59
|
-
get_context=self.get_context,
|
60
|
-
get_root_value=self.get_root_value,
|
61
|
-
process_result=self.process_result,
|
62
|
-
encode_json=self.encode_json,
|
63
|
-
).handle(scope=scope, receive=receive, send=send)
|
111
|
+
return await self.handle_http(scope, receive, send)
|
64
112
|
|
65
113
|
elif scope["type"] == "websocket":
|
66
114
|
ws = WebSocket(scope=scope, receive=receive, send=send)
|
@@ -102,16 +150,57 @@ class GraphQL:
|
|
102
150
|
return None
|
103
151
|
|
104
152
|
async def get_context(
|
153
|
+
self, request: Union[Request, WebSocket], response: Response
|
154
|
+
) -> Context:
|
155
|
+
return {"request": request, "response": response} # type: ignore
|
156
|
+
|
157
|
+
async def get_sub_response(
|
105
158
|
self,
|
106
159
|
request: Union[Request, WebSocket],
|
107
|
-
|
108
|
-
|
109
|
-
|
160
|
+
) -> Response:
|
161
|
+
sub_response = Response()
|
162
|
+
sub_response.status_code = None # type: ignore
|
163
|
+
del sub_response.headers["content-length"]
|
164
|
+
|
165
|
+
return sub_response
|
166
|
+
|
167
|
+
async def handle_http(
|
168
|
+
self,
|
169
|
+
scope: Scope,
|
170
|
+
receive: Receive,
|
171
|
+
send: Send,
|
172
|
+
) -> None:
|
173
|
+
request = Request(scope=scope, receive=receive)
|
174
|
+
|
175
|
+
try:
|
176
|
+
response = await self.run(request)
|
177
|
+
except HTTPException as e:
|
178
|
+
response = PlainTextResponse(
|
179
|
+
e.reason, status_code=e.status_code
|
180
|
+
) # pyright: ignore
|
181
|
+
|
182
|
+
await response(scope, receive, send)
|
183
|
+
|
184
|
+
def render_graphiql(self, request: Union[Request, WebSocket]) -> Response:
|
185
|
+
html = get_graphiql_html()
|
186
|
+
|
187
|
+
return HTMLResponse(html)
|
188
|
+
|
189
|
+
def create_response(
|
190
|
+
self, response_data: GraphQLHTTPResponse, sub_response: Response
|
191
|
+
) -> Response:
|
192
|
+
response = Response(
|
193
|
+
self.encode_json(response_data),
|
194
|
+
status_code=status.HTTP_200_OK,
|
195
|
+
media_type="application/json",
|
196
|
+
)
|
197
|
+
|
198
|
+
response.headers.raw.extend(sub_response.headers.raw)
|
199
|
+
|
200
|
+
if sub_response.background:
|
201
|
+
response.background = sub_response.background
|
110
202
|
|
111
|
-
|
112
|
-
|
113
|
-
) -> GraphQLHTTPResponse:
|
114
|
-
return process_result(result)
|
203
|
+
if sub_response.status_code:
|
204
|
+
response.status_code = sub_response.status_code
|
115
205
|
|
116
|
-
|
117
|
-
return json.dumps(response_data)
|
206
|
+
return response
|
@@ -2,6 +2,5 @@ from strawberry.asgi.handlers.graphql_transport_ws_handler import (
|
|
2
2
|
GraphQLTransportWSHandler,
|
3
3
|
)
|
4
4
|
from strawberry.asgi.handlers.graphql_ws_handler import GraphQLWSHandler
|
5
|
-
from strawberry.asgi.handlers.http_handler import HTTPHandler
|
6
5
|
|
7
|
-
__all__ = ["GraphQLTransportWSHandler", "GraphQLWSHandler"
|
6
|
+
__all__ = ["GraphQLTransportWSHandler", "GraphQLWSHandler"]
|