Skip to content

Commit a694bc0

Browse files
committed
Added support for options/cors
1 parent 408b9bc commit a694bc0

File tree

7 files changed

+44
-25
lines changed

7 files changed

+44
-25
lines changed

src/graphql_server/fastapi/router.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ async def handle_http_post( # pyright: ignore
254254
status_code=e.status_code,
255255
)
256256

257+
@self.options(path)
258+
async def handle_http_options( # pyright: ignore
259+
request: Request,
260+
response: Response,
261+
) -> Response:
262+
return Response(status_code=200)
263+
257264
@self.websocket(path)
258265
async def websocket_endpoint( # pyright: ignore
259266
websocket: WebSocket,

src/graphql_server/http/async_base_view.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,12 @@ async def create_websocket_response(
198198

199199
async def execute_operation(
200200
self,
201-
request: Request,
201+
request_adapter: AsyncHTTPRequestAdapter,
202202
request_data: GraphQLRequestData,
203203
context: Context,
204204
root_value: Optional[RootValue],
205205
allowed_operation_types: set[OperationType],
206206
) -> ExecutionResult:
207-
request_adapter = self.request_adapter_class(request)
208-
209207
assert self.schema
210208

211209
if request_data.protocol == "multipart-subscription":
@@ -279,17 +277,18 @@ async def run(
279277
context: Context = UNSET,
280278
root_value: Optional[RootValue] = UNSET,
281279
) -> Union[Response, WebSocketResponse]:
282-
root_value = (
283-
await self.get_root_value(request) if root_value is UNSET else root_value
284-
)
285-
286280
if self.is_websocket_request(request):
287281
websocket_subprotocol = await self.pick_websocket_subprotocol(request)
288282
websocket_response = await self.create_websocket_response(
289283
request, websocket_subprotocol
290284
)
291285
websocket = self.websocket_adapter_class(self, request, websocket_response)
292286

287+
root_value = (
288+
await self.get_root_value(request)
289+
if root_value is UNSET
290+
else root_value
291+
)
293292
context = (
294293
await self.get_context(request, response=websocket_response)
295294
if context is UNSET
@@ -324,7 +323,16 @@ async def run(
324323
request = cast("Request", request)
325324

326325
request_adapter = self.request_adapter_class(request)
326+
if request_adapter.method == "OPTIONS":
327+
# We are in a CORS preflight request, we can return a 200 OK by default
328+
# as further checks will need to be done by the middleware
329+
raise HTTPException(200, "")
330+
327331
sub_response = await self.get_sub_response(request)
332+
333+
root_value = (
334+
await self.get_root_value(request) if root_value is UNSET else root_value
335+
)
328336
context = (
329337
await self.get_context(request, response=sub_response)
330338
if context is UNSET
@@ -366,7 +374,7 @@ async def run(
366374
is_strict = request_data.protocol == "http-strict"
367375
try:
368376
result = await self.execute_operation(
369-
request=request,
377+
request_adapter=request_adapter,
370378
request_data=request_data,
371379
context=context,
372380
root_value=root_value,

src/graphql_server/http/sync_base_view.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,12 @@ def render_graphql_ide(
100100

101101
def execute_operation(
102102
self,
103-
request: Request,
103+
request_adapter: SyncHTTPRequestAdapter,
104104
request_data: GraphQLRequestData,
105105
context: Context,
106106
root_value: Optional[RootValue],
107107
allowed_operation_types: set[OperationType],
108108
) -> ExecutionResult:
109-
request_adapter = self.request_adapter_class(request)
110-
111109
assert self.schema
112110

113111
return execute_sync(
@@ -188,6 +186,10 @@ def run(
188186
root_value: Optional[RootValue] = UNSET,
189187
) -> Response:
190188
request_adapter = self.request_adapter_class(request)
189+
if request_adapter.method == "OPTIONS":
190+
# We are in a CORS preflight request, we can return a 200 OK by default
191+
# as further checks will need to be done by the middleware
192+
raise HTTPException(200, "")
191193

192194
if not self.is_request_allowed(request_adapter):
193195
raise HTTPException(405, "GraphQL only supports GET and POST requests.")
@@ -232,7 +234,7 @@ def run(
232234
is_strict = request_data.protocol == "http-strict"
233235
try:
234236
result = self.execute_operation(
235-
request=request,
237+
request_adapter=request_adapter,
236238
request_data=request_data,
237239
context=context,
238240
root_value=root_value,

src/graphql_server/litestar/controller.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -374,19 +374,6 @@ async def handle_http_post(
374374
root_value=root_value,
375375
)
376376

377-
@websocket()
378-
async def websocket_endpoint(
379-
self,
380-
socket: WebSocket,
381-
context_ws: Any,
382-
root_value: Any,
383-
) -> None:
384-
await self.run(
385-
request=socket,
386-
context=context_ws,
387-
root_value=root_value,
388-
)
389-
390377
async def get_context(
391378
self,
392379
request: Union[Request[Any, Any, Any], WebSocket],

src/graphql_server/sanic/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ async def get(self, request: Request) -> HTTPResponse:
194194
except HTTPException as e:
195195
return HTTPResponse(e.reason, status=e.status_code)
196196

197+
async def options(self, request: Request) -> HTTPResponse:
198+
return HTTPResponse(status=200)
199+
197200
async def create_streaming_response(
198201
self,
199202
request: Request,

src/tests/http/test_http.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,10 @@ async def test_the_http_handler_uses_the_views_decode_json_method(
3030
assert data["hello"] == "Hello world"
3131

3232
assert spy.call_count == 1
33+
34+
35+
async def test_does_allow_http_options(
36+
http_client: HttpClient,
37+
):
38+
response = await http_client.request(url="/graphql", method="options")
39+
assert response.status_code in (200, 204)

src/tests/litestar/app.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from graphql_server.litestar import make_graphql_controller
44
from litestar import Litestar, Request
55
from litestar.di import Provide
6+
from litestar.config.cors import CORSConfig
7+
68
from tests.views.schema import schema
79

810

@@ -27,9 +29,12 @@ def create_app(schema=schema, **kwargs: Any):
2729
**kwargs,
2830
)
2931

32+
cors_config = CORSConfig(allow_origins=["*"])
33+
3034
return Litestar(
3135
route_handlers=[GraphQLController],
3236
dependencies={
3337
"app_dependency": Provide(custom_context_dependency, sync_to_thread=True)
3438
},
39+
cors_config=cors_config,
3540
)

0 commit comments

Comments
 (0)