Ir para o conteúdo

Excepções & Exception Handlers

Exception handlers são, como o nome sugere, as funções que lidam com excepções do tipo X caso ocorram.

Exception handlers

Em cada nível o parâmetro exception_handler (entre outros) está disponível para ser utilizado e pronto a lidar com excepções espeíficas para cada nível.

As exception handlers são declaras num dicionário python e pode passar como chave a excepção em si ou o status_code que vai sempre utilizar a excepção em si.

from json import loads

from lilya import status
from lilya.apps import Lilya
from lilya.requests import Request
from lilya.responses import JSONResponse
from lilya.routing import Include, Path


async def handle_type_error(request: Request, exc: TypeError):
    status_code = status.HTTP_400_BAD_REQUEST
    details = loads(exc.json()) if hasattr(exc, "json") else exc.args[0]
    return JSONResponse({"detail": details}, status_code=status_code)


async def handle_value_error(request: Request, exc: ValueError):
    status_code = status.HTTP_400_BAD_REQUEST
    details = loads(exc.json()) if hasattr(exc, "json") else exc.args[0]
    return JSONResponse({"detail": details}, status_code=status_code)


async def me():
    return "Hello, world!"


app = Lilya(
    routes=[
        Include(
            "/",
            routes=[
                Path(
                    "/me",
                    handler=me,
                )
            ],
        )
    ],
    exception_handlers={
        TypeError: handle_type_error,
        ValueError: handle_value_error,
    },
)

O que está a acontecer

O nível da aplicação contém um manipulador de excepções handle_type_error e handle_value_error e isso significa que para toda HTTPException e ValueError lançada na aplicação, será tratada por essa função.

Exception handlers personalisadas

Todos sabemos que Lilya lida muito bem com excepções por design, mas às vezes também podemos querer lançar um erro ao fazer alguma lógica de código que não está diretamente relacionada com um data de um exception handler.

Examplo

from lilya.apps import Lilya
from lilya.requests import Request
from lilya.routing import Path


async def create(request: Request):
    data = await request.json()
    if len(data) == 0:
        raise ValueError("Cannot be 0.")


app = Lilya(
    routes=[
        Path(
            "/create",
            handler=create,
            methods=["POST"],
        )
    ],
)

Este exemplo não é nada comum, mas serve para mostrar onde uma excepção é lançada.

Lilya oferece um exception handler personalizado pronto a usar:

  • handle_value_error - Quando se quer que a excepção ValueError seja automaticamente convertida num JSON.
from lilya._internal._exception_handlers import handle_value_error

Como ficaria o exemplo anterior utilizando este exception handler personalizado?

from lilya._internal._exception_handlers import handle_value_error
from lilya.apps import Lilya
from lilya.requests import Request
from lilya.routing import Path


async def create(request: Request):
    data = await request.json()
    if len(data) == 0:
        raise ValueError("Cannot be 0.")


app = Lilya(
    routes=[Path("/create", handler=create)],
    exception_handlers={
        ValueError: handle_value_error,
    },
)

Uso dos status codes

Ao declarar exception handlers, como mencionado anteriormente, pode-se usar status codes em vez da própria excepção. Isto permite e indica como uma excepção deve ser tratada quando ocorre um status_code específico.

Isto pode ser muito útil se apenas se quiser restringir à abordagem do status_code em vez da própria Exception.

from lilya.apps import Lilya
from lilya.exceptions import HTTPException
from lilya.requests import Request
from lilya.responses import Error


async def not_found(request: Request, exc: HTTPException):
    return Error("Oops", status_code=exc.status_code)


async def server_error(request: Request, exc: HTTPException):
    return Error("Oops", status_code=exc.status_code)


app = Lilya(
    routes=...,
    exception_handlers={
        404: not_found,
        500: server_error,
    },
)

HTTPException

A classe HTTPException serve como uma classe fundamental adequada para lidar com várias excepções. Na implementação padrão do ExceptionMiddleware, respostas HTTP no formato de texto simples são retornadas em qualquer instância de HTTPException.

Note

O uso correto dita que se deve lançar o HTTPException exclusivamente dentro de rotas ou endpoints. Middleware e Permissões, por outro lado, devem simplesmente retornar as respostas apropriadas diretamente.

WebSocketException

A classe WebSocketException é desenhada para lançar erros especificamente dentro de endpoints WebSocket.