Кастомизация и расширение¶
Своя модель ответа¶
По умолчанию тело ошибки — {code, detail}. Чтобы добавить свои поля (например, конверт со status), наследуйте ErrorResponse дженерик-подклассом и укажите его в response_base своего базового класса ошибок.
from typing import Any, ClassVar, Literal
from fastapi_typed_errors import BaseError, ErrorResponse
class MyErrorResponse[T: str](ErrorResponse[T]):
status: Literal["error"] = "error" # (1)!
class AppError[T: str](BaseError[T]):
response_base: ClassVar[type[ErrorResponse[Any]]] = MyErrorResponse
class NotFoundError(AppError[Literal["NOT_FOUND"]]):
http_status = HTTPStatus.NOT_FOUND
- Дополнительное поле встаёт рядом с
code/detail.
Тело ответа станет:
Только плоское расширение
Форма должна оставаться плоской. Вложенные конверты вида {"status": ..., "data": {"code": ...}} не поддерживаются: pydantic-овские discriminated union требуют, чтобы дискриминатор code был на верхнем уровне модели, иначе error_models() для нескольких ошибок на одном статусе сломается.
Голые строковые коды¶
Enum приносите свой — но он не обязателен. Код может быть голой строкой в Literal:
StrEnum удобнее, когда кодов много и хочется единый реестр; голый Literal — для разовых случаев.
description и заголовки¶
description: ClassVar[str | None]— дефолтныйdetailи описание статуса в OpenAPI.- Заголовки прокидываются в
HTTPException:
class RequiredTokenError(BaseError[Literal["REQUIRED_TOKEN"]]):
http_status = HTTPStatus.UNAUTHORIZED
description = "Требуется токен"
raise RequiredTokenError(headers={"WWW-Authenticate": "Bearer"})
Промежуточные базы¶
Общую конфигурацию (свой response_base, общий префикс кодов) выносите в промежуточную дженерик-базу — она параметризуется TypeVar и не обязана объявлять код:
class AppError[T: str](BaseError[T]):
response_base = MyErrorResponse
# http_status здесь не нужен — это не конкретная ошибка
class NotFoundError(AppError[Literal["NOT_FOUND"]]):
http_status = HTTPStatus.NOT_FOUND
Метакласс пропускает базы, параметризованные TypeVar, и выводит error_code/model только у конкретных подклассов.
Совместимость с ABC¶
BaseError наследует HTTPException и использует метакласс BaseErrorMeta. Если смешать его с ABC (у которого свой ABCMeta), Python выдаст конфликт метаклассов. Решение — комбинированный метакласс:
from abc import ABCMeta, abstractmethod
from fastapi_typed_errors.core.base import BaseErrorMeta # (1)!
class ABCErrorMeta(BaseErrorMeta, ABCMeta): ...
class AbstractError[T: str](BaseError[T], metaclass=ABCErrorMeta):
@abstractmethod
def audit(self) -> None: ...
BaseErrorMetaнамеренно не реэкспортируется из корня пакета — импортируйте изfastapi_typed_errors.core.base.
Явная регистрация — это принцип¶
Пакет не прячет магию за install(app)-хелперами. Обработчик вешается руками:
Это тот же стиль, что app.add_middleware(...): настройка приложения остаётся явной и под вашим контролем.
Дальше: Рецепты — частые практические паттерны.