Exceptions¶
Esmerald comes with some built-in exceptions but also allows you to install custom exception handlers to deal with how you return responses when exceptions happen.
HTTPException¶
The HTTPException
object serves as base that can be used for any handled exception from Esmerald.
from esmerald.exceptions import HTTPException
ImproperlyConfigured¶
The name might be familiar for some of the developers out there and it is intentional as it is also self explanatory. Inherits from the base HTTPException and it is raised when a misconfiguration occurs.
from esmerald.exceptions import ImproperlyConfigured
Status code: 500
NotAuthenticated¶
Exception raised when an a resources that depends of an authenticated user does not exist.
from esmerald.exceptions import NotAuthenticated
Status code: 401
PermissionDenied¶
Exception raised when a permission fails. It can be used in any context also outside of the permissions context and it should be raised any time the access to a resource should be blocked.
from esmerald.exceptions import PermissionDenied
Status code: 403
ValidationErrorException¶
ValidationErrorException
is part of the Esmerald default exception_handlers
by design and it is part of its core when
a validation, for example, from pydantic models, occurs.
from esmerald.exceptions import ValidationErrorException
Status code: 400
NotAuthorized¶
Exception raised when an authentication fails. It is very useful for any authentication middleware process and it is encouraged to be applied in any custom middleware handling with similar processes.
from esmerald.exceptions import NotAuthorized
Status code: 401
NotFound¶
Classic and self explanatory exception. Useful when a resource is not found or a simple 404 needs to be raised.
from esmerald.exceptions import NotFound
Status code: 404
MethodNotAllowed¶
Very useful exception to be used, as already is, to raise exceptions when an HTTP method is not allows on a given Gateway.
from esmerald.exceptions import MethodNotAllowed
Status code: 405
InternalServerError¶
Used internally for internal server error and it raises a descriptive message in the browser if debug=True
.
from esmerald.exceptions import InternalServerError
Status code: 500
ServiceUnavailable¶
It should be used to be raised when a resource is not available.
from esmerald.exceptions import ServiceUnavailable
Status code: 503
Custom exceptions¶
Every application has different needs, errors, operations and everything else. Although the default Esmerald exceptions work for generic and internal processing you might face an issue when it comes to handle some specifc, more narrow and unique to your application type of exception. This is very simple and also very possible.
from typing import Optional
from pydantic import BaseModel
from starlette import status
from esmerald import HTTPException, JSONResponse, Request, post
class PartialContentException(HTTPException):
status_code = status.HTTP_206_PARTIAL_CONTENT
detail = "Incomplete data."
async def validation_error_exception_handler(
request: Request, exc: PartialContentException
) -> JSONResponse:
extra = getattr(exc, "extra", None)
if extra:
return JSONResponse(
{"detail": exc.detail, "errors": exc.extra.get("extra", {})},
status_code=status.HTTP_400_BAD_REQUEST,
)
else:
return JSONResponse(
{"detail": exc.detail},
status_code=status.HTTP_400_BAD_REQUEST,
)
class User(BaseModel):
name: Optional[str]
email: Optional[str]
@post(
"/create",
exception_handlers={PartialContentException: validation_error_exception_handler},
)
async def create_user(data: User):
if not data.user:
raise PartialContentException()
else:
...
The example above of course is forced to be like that for illustration purposes to raise the custom exception as the
default if no Optional
fields were declared would be handled by Esmerald ValidationErrorException
exception
handler but this serves as an example how to do your own.
Overriding the current Esmerald exception handlers¶
Currently by default, every Esmerald application starts with ImproperlyConfigured
and ValidationErrorException
to make sure everything is covered accordingly but this does not necessarily mean that this can't be changed.
from pydantic.error_wrappers import ValidationError
from starlette import status
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.responses import Response as StarletteResponse
from esmerald import (
HTTPException,
ImproperlyConfigured,
JSONResponse,
Request,
Response,
ValidationErrorException,
)
from esmerald.applications import Esmerald
from esmerald.enums import MediaType
async def improperly_configured_exception_handler(
request: Request, exc: ImproperlyConfigured
) -> StarletteResponse:
status_code = (
exc.status_code
if isinstance(exc, StarletteHTTPException)
else status.HTTP_500_INTERNAL_SERVER_ERROR
)
if not status_code:
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
content = {"detail": exc.detail}
if exc.extra:
content.update({"extra": exc.extra})
headers = exc.headers if isinstance(exc, (HTTPException, StarletteHTTPException)) else None
return Response(
media_type=MediaType.JSON,
content=content,
status_code=status_code,
headers=headers,
)
async def validation_error_exception_handler(
request: Request, exc: ValidationError
) -> JSONResponse:
extra = getattr(exc, "extra", None)
if extra:
return JSONResponse(
{"detail": exc.detail, "errors": exc.extra.get("extra", {})},
status_code=status.HTTP_400_BAD_REQUEST,
)
else:
return JSONResponse(
{"detail": exc.detail},
status_code=status.HTTP_400_BAD_REQUEST,
)
app = Esmerald(
routes=[...],
exception_handlers={
ImproperlyConfigured: improperly_configured_exception_handler,
ValidationErrorException: validation_error_exception_handler,
},
)
This will make sure that the application defaults will have a your exception_handler instead of the main application.
API Reference¶
Check out the API Reference for HTTPException for more details.