Skip to content

Commit 55698fd

Browse files
fix: graphql response status code
1 parent f9a95a3 commit 55698fd

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
@@ -443,18 +443,22 @@ async def create_json_response(
443443
"""Creates JSON response from GraphQL's query result.
444444
445445
Returns Starlette's `JSONResponse` instance that's also compatible
446-
with FastAPI. If `success` is `True`, response's status code is 200.
447-
Status code 400 is used otherwise.
446+
with FastAPI. If `success` is `True` or the result contains non-null
447+
'data' (indicating execution was attempted and produced results),
448+
response's status code is 200. Status code 400 is used otherwise.
448449
449450
# Required arguments
450451
451452
`request`: the `Request` instance from Starlette or FastAPI.
452453
453454
`result`: a JSON-serializable `dict` with query result.
454455
455-
`success`: a `bool` specifying if
456+
`success`: a `bool` specifying if query execution was successful.
456457
"""
457-
status_code = HTTPStatus.OK if success else HTTPStatus.BAD_REQUEST
458+
if success or result.get("data") is not None:
459+
status_code = HTTPStatus.OK
460+
else:
461+
status_code = HTTPStatus.BAD_REQUEST
458462
return JSONResponse(result, status_code=status_code)
459463

460464
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
@@ -567,7 +567,7 @@ def handle_query_result(
567567
if result.errors:
568568
extension_manager.has_errors(result.errors)
569569
add_extensions_to_response(extension_manager, response)
570-
return not result.errors, response
570+
return result.data is not None, response
571571

572572

573573
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
@@ -126,16 +126,18 @@ async def test_graphql_executes_the_query_using_result_update_obj(schema):
126126
}
127127

128128

129-
def test_graphql_sync_returns_false_success_when_execution_produces_errors(schema):
129+
def test_graphql_sync_returns_true_success_when_execution_produces_errors(schema):
130130
success, result = graphql_sync(schema, {"query": "{ testError }"})
131-
assert not success
131+
assert success
132+
assert result["data"] is not None
132133
assert result["errors"]
133134

134135

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

141143

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)