Skip to content

Commit a33c49f

Browse files
fix: graphql response status code
(cherry picked from commit 55698fd)
1 parent 4e49360 commit a33c49f

7 files changed

Lines changed: 56 additions & 16 deletions

File tree

ariadne/asgi/handlers/http.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,18 +452,22 @@ async def create_json_response(
452452
"""Creates JSON response from GraphQL's query result.
453453
454454
Returns Starlette's `JSONResponse` instance that's also compatible
455-
with FastAPI. If `success` is `True`, response's status code is 200.
456-
Status code 400 is used otherwise.
455+
with FastAPI. If `success` is `True` or the result contains non-null
456+
'data' (indicating execution was attempted and produced results),
457+
response's status code is 200. Status code 400 is used otherwise.
457458
458459
# Required arguments
459460
460461
`request`: the `Request` instance from Starlette or FastAPI.
461462
462463
`result`: a JSON-serializable `dict` with query result.
463464
464-
`success`: a `bool` specifying if
465+
`success`: a `bool` specifying if query execution was successful.
465466
"""
466-
status_code = HTTPStatus.OK if success else HTTPStatus.BAD_REQUEST
467+
if success or result.get("data") is not None:
468+
status_code = HTTPStatus.OK
469+
else:
470+
status_code = HTTPStatus.BAD_REQUEST
467471
return JSONResponse(result, status_code=status_code)
468472

469473
def handle_not_allowed_method(self, request: Request):

ariadne/graphql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ def handle_query_result(
587587
if result.errors:
588588
extension_manager.has_errors(result.errors)
589589
add_extensions_to_response(extension_manager, response)
590-
return not result.errors, response
590+
return result.data is not None, response
591591

592592

593593
def handle_graphql_errors(

ariadne/wsgi.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -546,11 +546,10 @@ def return_response_from_result(
546546
`result`: a `GraphQLResult` for this request.
547547
"""
548548
success, response = result
549-
status_str = (
550-
HttpStatusResponse.OK.value
551-
if success
552-
else HttpStatusResponse.BAD_REQUEST.value
553-
)
549+
if success or response.get("data") is not None:
550+
status_str = HttpStatusResponse.OK.value
551+
else:
552+
status_str = HttpStatusResponse.BAD_REQUEST.value
554553
start_response(status_str, [("Content-Type", CONTENT_TYPE_JSON)])
555554
return [json.dumps(response).encode("utf-8")]
556555

tests/asgi/__snapshots__/test_query_execution.ambr

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,24 @@
138138
}),
139139
})
140140
# ---
141+
# name: test_query_with_execution_errors_returns_200_status_code
142+
dict({
143+
'data': dict({
144+
'testError': None,
145+
}),
146+
'errors': list([
147+
dict({
148+
'locations': list([
149+
dict({
150+
'column': 3,
151+
'line': 1,
152+
}),
153+
]),
154+
'message': 'Test exception',
155+
'path': list([
156+
'testError',
157+
]),
158+
}),
159+
]),
160+
})
161+
# ---

tests/asgi/test_query_execution.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,20 @@ def test_middleware(next_fn, *args, **kwargs):
228228
assert response.json() == {"data": {"hello": "=*Hello, BOB!*="}}
229229

230230

231+
def test_query_with_execution_errors_returns_200_status_code(client, snapshot):
232+
response = client.post("/", json={"query": "{ testError }"})
233+
assert response.status_code == HTTPStatus.OK
234+
assert snapshot == response.json()
235+
236+
237+
def test_query_with_syntax_error_returns_400_status_code(client):
238+
"""Unparseable query produces no data entry → 400 per GraphQL over HTTP spec."""
239+
response = client.post("/", json={"query": "{ invalid syntax !!@ }"})
240+
assert response.status_code == HTTPStatus.BAD_REQUEST
241+
assert "data" not in response.json()
242+
assert response.json()["errors"]
243+
244+
231245
def test_schema_not_set(client, snapshot):
232246
client.app.http_handler.schema = None
233247
with pytest.raises(TypeError):

tests/test_graphql.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,18 @@ async def test_graphql_executes_the_query_using_result_update_obj(schema):
127127
}
128128

129129

130-
def test_graphql_sync_returns_false_success_when_execution_produces_errors(schema):
130+
def test_graphql_sync_returns_true_success_when_execution_produces_errors(schema):
131131
success, result = graphql_sync(schema, {"query": "{ testError }"})
132-
assert not success
132+
assert success
133+
assert result["data"] is not None
133134
assert result["errors"]
134135

135136

136137
@pytest.mark.asyncio
137-
async def test_graphql_returns_false_success_when_execution_produces_errors(schema):
138+
async def test_graphql_returns_true_success_when_execution_produces_errors(schema):
138139
success, result = await graphql(schema, {"query": "{ testError }"})
139-
assert not success
140+
assert success
141+
assert result["data"] is not None
140142
assert result["errors"]
141143

142144

tests/wsgi/test_request_data_reading.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def test_attempt_parse_json_scalar_request_raises_graphql_bad_request_error(
126126
request = graphql_query_request_factory(raw_data=json.dumps("json string"))
127127
result = middleware(request, start_response)
128128
start_response.assert_called_once_with(
129-
HttpBadRequestError().status, graphql_response_headers
129+
HttpStatusResponse.BAD_REQUEST.value, graphql_response_headers
130130
)
131131
assert_json_response_equals_snapshot(result)
132132

@@ -141,7 +141,7 @@ def test_attempt_parse_json_array_request_raises_graphql_bad_request_error(
141141
request = graphql_query_request_factory(raw_data=json.dumps([1, 2, 3]))
142142
result = middleware(request, start_response)
143143
start_response.assert_called_once_with(
144-
HttpBadRequestError().status, graphql_response_headers
144+
HttpStatusResponse.BAD_REQUEST.value, graphql_response_headers
145145
)
146146
assert_json_response_equals_snapshot(result)
147147

0 commit comments

Comments
 (0)