Перейти к содержанию

fastapi-typed-errors

Типизированные HTTP-ошибки для FastAPI. Точные Literal-коды в OpenAPI, discriminated oneOf-union по полю code и единый источник правды — сам класс ошибки.


Зачем это нужно

В обычном FastAPI ошибка — это HTTPException(404, "..."). Код ошибки живёт в строке, в OpenAPI нет ни типа кода, ни модели тела ответа, а список возможных ошибок роута приходится вручную дублировать в responses={}. Клиент не может переключиться по коду, а документация быстро расходится с кодом.

fastapi-typed-errors делает ошибку классом: HTTP-статус, машинный код и модель ответа объявляются один раз и выводятся автоматически.

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id == 0:
        raise HTTPException(404, "No item")  # (1)!
    return {"item_id": item_id}
  1. Код ошибки — просто строка в detail; в OpenAPI у 404 нет ни точного кода, ни схемы тела.
class NotFoundError(BaseError[Literal[ErrorCode.NOT_FOUND]]):
    http_status = HTTPStatus.NOT_FOUND


@router.get("/items/{item_id}")
def get_item(item_id: int) -> Annotated[Item, Raises[NotFoundError]]:  # (1)!
    if item_id == 0:
        raise NotFoundError("No item")
    return Item(item_id=item_id)
  1. Задекларированная ошибка попадает в responses автоматически: 404 с точным Literal["NOT_FOUND"] и телом {code, detail}.
router = with_errors(APIRouter(), auto=True)  # (1)!


@router.get("/items/{item_id}")
def get_item(item_id: int) -> Item:  # (2)!
    if item_id == 0:
        raise NotFoundError("No item")
    return Item(item_id=item_id)
  1. Включаем авто-заполнение один раз на роутере.
  2. Ни одного маркера — responses соберутся сами: обходчик найдёт raise NotFoundError (и ошибки из зависимостей) статически. См. auto=True.

Тело ответа всегда предсказуемо:

{ "code": "NOT_FOUND", "detail": "No item" }

А в OpenAPI роут получает по записи на каждый статус — с точным кодом и моделью тела. Вот как это отображается в Swagger UI:

Панель Responses в Swagger UI: 200 → Item, 403 → ErrorResponse[FORBIDDEN], 404 → oneOf ErrorResponse[NOT_FOUND] / ErrorResponse[GONE] с дискриминатором по code

Возможности

  • Единый источник правды


    Статус, код и модель ответа объявляются один раз в классе ошибки. Метакласс выводит остальное.

    Ядро

  • Точные типы в OpenAPI


    Каждый статус получает точный Literal-код; несколько ошибок на статус — discriminated oneOf-union по code.

    error_models

  • Декларация прямо в аннотации


    -> Annotated[Item, Raises[NotFoundError, ForbiddenError]] — и responses заполняются сами.

    Декоратор

  • CI-проверка контрактов


    check_raises сверяет задекларированное с реально поднимаемым — в эндпоинте и его зависимостях.

    CI-checker

  • Авто-заполнение


    with_errors(router, auto=True) находит ошибки статически и заполняет responses без единого маркера.

    auto=True

  • Расширяемость


    Своя модель ответа-конверта, свои коды (StrEnum или голый Literal), совместимость с ABC.

    Кастомизация

Установка

uv add fastapi-typed-errors
# с CLI для CI-проверки:
uv add "fastapi-typed-errors[cli]"
pip install fastapi-typed-errors
pip install "fastapi-typed-errors[cli]"

Требования

  • Python 3.12+ (PEP 695-дженерики)
  • FastAPI ≥ 0.115 (версии 0.1370.138 исключены — см. Ограничения)
  • Pydantic ≥ 2.9

Дальше