Browse Source

Merge f460a756fa into 460f8d2cc8

pull/14400/merge
Javier Sánchez Castro 12 hours ago
committed by GitHub
parent
commit
b2dc3ead2f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      fastapi/applications.py
  2. 15
      fastapi/exception_handlers.py
  3. 12
      fastapi/exceptions.py
  4. 6
      fastapi/routing.py
  5. 2
      tests/test_tutorial/test_body/test_tutorial001.py

10
fastapi/applications.py

@ -7,10 +7,15 @@ from fastapi import routing
from fastapi.datastructures import Default, DefaultPlaceholder from fastapi.datastructures import Default, DefaultPlaceholder
from fastapi.exception_handlers import ( from fastapi.exception_handlers import (
http_exception_handler, http_exception_handler,
request_malformed_exception_handler,
request_validation_exception_handler, request_validation_exception_handler,
websocket_request_validation_exception_handler, websocket_request_validation_exception_handler,
) )
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.exceptions import (
RequestMalformedError,
RequestValidationError,
WebSocketRequestValidationError,
)
from fastapi.logger import logger from fastapi.logger import logger
from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware
from fastapi.openapi.docs import ( from fastapi.openapi.docs import (
@ -999,6 +1004,9 @@ class FastAPI(Starlette):
Any, Callable[[Request, Any], Response | Awaitable[Response]] Any, Callable[[Request, Any], Response | Awaitable[Response]]
] = {} if exception_handlers is None else dict(exception_handlers) ] = {} if exception_handlers is None else dict(exception_handlers)
self.exception_handlers.setdefault(HTTPException, http_exception_handler) self.exception_handlers.setdefault(HTTPException, http_exception_handler)
self.exception_handlers.setdefault(
RequestMalformedError, request_malformed_exception_handler
)
self.exception_handlers.setdefault( self.exception_handlers.setdefault(
RequestValidationError, request_validation_exception_handler RequestValidationError, request_validation_exception_handler
) )

15
fastapi/exception_handlers.py

@ -1,5 +1,9 @@
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError from fastapi.exceptions import (
RequestMalformedError,
RequestValidationError,
WebSocketRequestValidationError,
)
from fastapi.utils import is_body_allowed_for_status_code from fastapi.utils import is_body_allowed_for_status_code
from fastapi.websockets import WebSocket from fastapi.websockets import WebSocket
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
@ -17,6 +21,15 @@ async def http_exception_handler(request: Request, exc: HTTPException) -> Respon
) )
async def request_malformed_exception_handler(
request: Request, exc: RequestMalformedError
) -> JSONResponse:
return JSONResponse(
status_code=400,
content={"detail": jsonable_encoder(exc.errors())},
)
async def request_validation_exception_handler( async def request_validation_exception_handler(
request: Request, exc: RequestValidationError request: Request, exc: RequestValidationError
) -> JSONResponse: ) -> JSONResponse:

12
fastapi/exceptions.py

@ -209,6 +209,18 @@ class ValidationException(Exception):
return message.rstrip() return message.rstrip()
class RequestMalformedError(ValidationException):
def __init__(
self,
errors: Sequence[Any],
*,
body: Any = None,
endpoint_ctx: Optional[EndpointContext] = None,
) -> None:
super().__init__(errors, endpoint_ctx=endpoint_ctx)
self.body = body
class RequestValidationError(ValidationException): class RequestValidationError(ValidationException):
def __init__( def __init__(
self, self,

6
fastapi/routing.py

@ -54,6 +54,7 @@ from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import ( from fastapi.exceptions import (
EndpointContext, EndpointContext,
FastAPIError, FastAPIError,
RequestMalformedError,
RequestValidationError, RequestValidationError,
ResponseValidationError, ResponseValidationError,
WebSocketRequestValidationError, WebSocketRequestValidationError,
@ -425,7 +426,7 @@ def get_request_handler(
else: else:
body = body_bytes body = body_bytes
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
validation_error = RequestValidationError( raise RequestMalformedError(
[ [
{ {
"type": "json_invalid", "type": "json_invalid",
@ -437,8 +438,7 @@ def get_request_handler(
], ],
body=e.doc, body=e.doc,
endpoint_ctx=endpoint_ctx, endpoint_ctx=endpoint_ctx,
) ) from e
raise validation_error from e
except HTTPException: except HTTPException:
# If a middleware raises an HTTPException, it should be raised again # If a middleware raises an HTTPException, it should be raised again
raise raise

2
tests/test_tutorial/test_body/test_tutorial001.py

@ -142,7 +142,7 @@ def test_post_broken_body(client: TestClient):
headers={"content-type": "application/json"}, headers={"content-type": "application/json"},
content="{some broken json}", content="{some broken json}",
) )
assert response.status_code == 422, response.text assert response.status_code == 400, response.text
assert response.json() == { assert response.json() == {
"detail": [ "detail": [
{ {

Loading…
Cancel
Save