Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replaced-http-statuses-with-HTTPStatus-from-http-stdlib #1174

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 0.24 (UNRELEASED)

- Added validation for directive declarations in `make_executable_schema` to prevent schema creation with undeclared directives.
- Replaced http statuses with HTTPStatus from http stdlib
DamianCzajkowski marked this conversation as resolved.
Show resolved Hide resolved


## 0.23 (2024-03-18)
Expand Down
9 changes: 6 additions & 3 deletions ariadne/asgi/handlers/http.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from http import HTTPStatus
DamianCzajkowski marked this conversation as resolved.
Show resolved Hide resolved
import json
from inspect import isawaitable
from typing import Any, Optional, Type, Union, cast
Expand Down Expand Up @@ -164,7 +165,9 @@ async def graphql_http_server(self, request: Request) -> Response:
try:
data = await self.extract_data_from_request(request)
except HttpError as error:
return PlainTextResponse(error.message or error.status, status_code=400)
return PlainTextResponse(
error.message or error.status, status_code=HTTPStatus.BAD_REQUEST
)

success, result = await self.execute_graphql_query(request, data)
return await self.create_json_response(request, result, success)
Expand Down Expand Up @@ -402,7 +405,7 @@ async def create_json_response(

`success`: a `bool` specifying if
"""
status_code = 200 if success else 400
status_code = HTTPStatus.OK if success else HTTPStatus.BAD_REQUEST
return JSONResponse(result, status_code=status_code)

def handle_not_allowed_method(self, request: Request):
Expand All @@ -423,4 +426,4 @@ def handle_not_allowed_method(self, request: Request):
if request.method == "OPTIONS":
return Response(headers=allow_header)

return Response(status_code=405, headers=allow_header)
return Response(status_code=HTTPStatus.METHOD_NOT_ALLOWED, headers=allow_header)
4 changes: 0 additions & 4 deletions ariadne/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,3 @@
CONTENT_TYPE_JSON = "application/json; charset=UTF-8"
CONTENT_TYPE_TEXT_HTML = "text/html; charset=UTF-8"
CONTENT_TYPE_TEXT_PLAIN = "text/plain; charset=UTF-8"

HTTP_STATUS_200_OK = "200 OK"
HTTP_STATUS_400_BAD_REQUEST = "400 Bad Request"
HTTP_STATUS_405_METHOD_NOT_ALLOWED = "405 Method Not Allowed"
20 changes: 10 additions & 10 deletions ariadne/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
from http import HTTPStatus
DamianCzajkowski marked this conversation as resolved.
Show resolved Hide resolved
import os
from typing import Optional, Union

from .constants import HTTP_STATUS_400_BAD_REQUEST


class HttpError(Exception):
"""Base class for HTTP errors raised inside the ASGI and WSGI servers."""

status = ""

def __init__(self, message: Optional[str] = None) -> None:
"""Initializes the `HttpError` with optional error message.
def __init__(self, status: HTTPStatus, message: Optional[str] = None) -> None:
"""Initializes the `HttpError` with a status and optional error message.

# Optional arguments
# Arguments

`message`: a `str` with error message to return in response body or
`None`.
`status`: HTTP status code as `HTTPStatus`.
`message`: Optional error message to return in the response body.
"""
super().__init__()
self.status = status
self.message = message


class HttpBadRequestError(HttpError):
"""Raised when request did not contain the data required to execute
the GraphQL query."""

status = HTTP_STATUS_400_BAD_REQUEST
def __init__(self, message: Optional[str] = None) -> None:
"""Initializes the `HttpBadRequestError` with optional error message."""
super().__init__(HTTPStatus.BAD_REQUEST, message)


class GraphQLFileSyntaxError(Exception):
Expand Down
17 changes: 6 additions & 11 deletions ariadne/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from inspect import isawaitable
from typing import Any, Callable, Dict, List, Optional, Type, Union, cast
from urllib.parse import parse_qsl

from http import HTTPStatus
DamianCzajkowski marked this conversation as resolved.
Show resolved Hide resolved
from graphql import (
ExecutionContext,
GraphQLError,
Expand All @@ -16,9 +16,6 @@
CONTENT_TYPE_TEXT_PLAIN,
DATA_TYPE_JSON,
DATA_TYPE_MULTIPART,
HTTP_STATUS_200_OK,
HTTP_STATUS_400_BAD_REQUEST,
HTTP_STATUS_405_METHOD_NOT_ALLOWED,
)
from .exceptions import HttpBadRequestError, HttpError
DamianCzajkowski marked this conversation as resolved.
Show resolved Hide resolved
from .explorer import Explorer, ExplorerGraphiQL
Expand Down Expand Up @@ -205,9 +202,7 @@

`start_response`: a callable used to begin new HTTP response.
"""
start_response(
HTTP_STATUS_400_BAD_REQUEST, [("Content-Type", CONTENT_TYPE_JSON)]
)
start_response(HTTPStatus.BAD_REQUEST, [("Content-Type", CONTENT_TYPE_JSON)])

Check warning on line 205 in ariadne/wsgi.py

View check run for this annotation

Codecov / codecov/patch

ariadne/wsgi.py#L205

Added line #L205 was not covered by tests
error_json = {"errors": [{"message": error.message}]}
return [json.dumps(error_json).encode("utf-8")]

Expand Down Expand Up @@ -319,7 +314,7 @@
if not explorer_html:
return self.handle_not_allowed_method(environ, start_response)

start_response(HTTP_STATUS_200_OK, [("Content-Type", CONTENT_TYPE_TEXT_HTML)])
start_response(HTTPStatus.OK, [("Content-Type", CONTENT_TYPE_TEXT_HTML)])
return [cast(str, explorer_html).encode("utf-8")]

def handle_post(self, environ: dict, start_response: Callable) -> List[bytes]:
Expand Down Expand Up @@ -558,7 +553,7 @@
`result`: a `GraphQLResult` for this request.
"""
success, response = result
status_str = HTTP_STATUS_200_OK if success else HTTP_STATUS_400_BAD_REQUEST
status_str = HTTPStatus.OK if success else HTTPStatus.BAD_REQUEST
start_response(status_str, [("Content-Type", CONTENT_TYPE_JSON)])
return [json.dumps(response).encode("utf-8")]

Expand All @@ -581,9 +576,9 @@
allowed_methods.append("GET")

if environ["REQUEST_METHOD"] == "OPTIONS":
status_str = HTTP_STATUS_200_OK
status_str = HTTPStatus.OK
else:
status_str = HTTP_STATUS_405_METHOD_NOT_ALLOWED
status_str = HTTPStatus.METHOD_NOT_ALLOWED

headers = [
("Content-Type", CONTENT_TYPE_TEXT_PLAIN),
Expand Down
10 changes: 6 additions & 4 deletions benchmark/test_extensions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from http import HTTPStatus

from starlette.testclient import TestClient

from ariadne.asgi import GraphQL
Expand All @@ -23,7 +25,7 @@ def api_call():
)

result = benchmark(api_call)
assert result.status_code == 200
assert result.status_code == HTTPStatus.OK
assert not result.json().get("errors")


Expand All @@ -45,7 +47,7 @@ def api_call():
)

result = benchmark(api_call)
assert result.status_code == 200
assert result.status_code == HTTPStatus.OK
assert not result.json().get("errors")


Expand All @@ -67,7 +69,7 @@ def api_call():
)

result = benchmark(api_call)
assert result.status_code == 200
assert result.status_code == HTTPStatus.OK
assert not result.json().get("errors")


Expand All @@ -89,5 +91,5 @@ def api_call():
)

result = benchmark(api_call)
assert result.status_code == 200
assert result.status_code == HTTPStatus.OK
assert not result.json().get("errors")
5 changes: 3 additions & 2 deletions tests/asgi/test_configuration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# pylint: disable=not-context-manager
from http import HTTPStatus
DamianCzajkowski marked this conversation as resolved.
Show resolved Hide resolved
import time
from datetime import timedelta
from unittest.mock import ANY, Mock
Expand Down Expand Up @@ -391,15 +392,15 @@ def test_query_over_get_fails_if_variables_are_not_json_serialized(schema):
"&operationName=Hello"
'&variables={"name" "John"}'
)
assert response.status_code == 400
assert response.status_code == HTTPStatus.BAD_REQUEST
assert response.content == b"Variables query arg is not a valid JSON"


def test_query_over_get_is_not_executed_if_not_enabled(schema):
app = GraphQL(schema, execute_get_queries=False)
client = TestClient(app)
response = client.get("/?query={ status }")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert response.headers["CONTENT-TYPE"] == "text/html; charset=utf-8"


Expand Down
10 changes: 6 additions & 4 deletions tests/asgi/test_explorer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from http import HTTPStatus

from starlette.testclient import TestClient

from ariadne.explorer import (
Expand All @@ -13,31 +15,31 @@ def test_default_explorer_html_is_served_on_get_request(schema, snapshot):
app = GraphQL(schema)
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert snapshot == response.text


def test_apollo_html_is_served_on_get_request(schema, snapshot):
app = GraphQL(schema, explorer=ExplorerApollo())
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert snapshot == response.text


def test_graphiql_html_is_served_on_get_request(schema, snapshot):
app = GraphQL(schema, explorer=ExplorerGraphiQL())
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert snapshot == response.text


def test_playground_html_is_served_on_get_request(schema, snapshot):
app = GraphQL(schema, explorer=ExplorerPlayground())
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert snapshot == response.text


Expand Down
6 changes: 4 additions & 2 deletions tests/asgi/test_http_methods.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from http import HTTPStatus

from starlette.testclient import TestClient

from ariadne.asgi import GraphQL


def test_options_method_is_supported(client):
response = client.options("/")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert response.headers["Allow"] == "OPTIONS, POST, GET"


Expand All @@ -14,7 +16,7 @@ def test_options_response_excludes_get_if_introspection_is_disabled(schema):
client = TestClient(app)

response = client.options("/")
assert response.status_code == 200
assert response.status_code == HTTPStatus.OK
assert response.headers["Allow"] == "OPTIONS, POST"


Expand Down
Loading
Loading