Fastapi. Как отловить исключение валидации базового класса

У меня есть стандартный роутер fastapi в котором я принимаю параметры пагинации через стандартный класс fastapi Params из пакета fastapi_pagination. Делаю я это так:

@router.get('/test', response_model=Page[Foo])
async def get_users(
    params: Params = Depends(),
    filter: Filter = FilterDepends(Filter),
) -> Any:
    pass

Все работает замечательно, но если я из postman передаю size > 100 то у меня вылетает

pydantic_core._pydantic_core.ValidationError: 1 validation error for Params

Это связано, как я думаю, с тем что внутри класса Params есть код:

class Params(BaseModel, AbstractParams):
    page: int = Query(1, ge=1, description="Page number")
    size: int = Query(50, ge=1, le=100, description="Page size")

    def to_raw_params(self) -> RawParams:
        return RawParams(
            limit=self.size,
            offset=self.size * (self.page - 1),
        )

Я пробовал уже менять явную типизацию Params на Any, Пробовал сразу устанавливать для этого параметра значения None, или писать свою функцию обработчик, подставляя в Depends(my_func). Максимум чего добился это возвращения ошибки на английском.

Мне бы хотелось как то отлавливать это исключение и оборачивать с свое кастомное исключение. Как можно это сделать?


Ответы (1 шт):

Автор решения: Arty Mart

В общем, проще всего было сделать свой кастомный Middleware перехватичк ошибок:

"""Кастомный обработчик ошибок"""
from typing import Any

from fastapi import Request
from pydantic import ValidationError
from starlette import status
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse


class ParamsExceptionHandler(BaseHTTPMiddleware):
"""Кастомный класс для обработки ошибок связанных с валидацией класса Params"""

    async def dispatch(self, request: Request, call_next: Any) -> Any:
        """
        Обрабатывает исключения, возникающие при валидации параметров классом Params.
        Request (Request): Запрос.
        Call_next (Any): Следующий обработчик запроса.

        Returns (Any): Результат обработки запроса или соответствующий JSONResponse в случае ошибки.
        """
        try:
            response = await call_next(request)
            return response
        except ValidationError as e:
            if "Params" in repr(e):
                return JSONResponse(
                    status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                    content={"detail": "detail")
            
            return JSONResponse(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                content={"detail": 'Internal Server Error'})

Главное не забыть добавить свой обработчик в middleware вашего приложения fastapi

→ Ссылка