Skip to main content

Typed error responses for FastAPI: Literal error codes, discriminated unions in OpenAPI, single source of truth

Project description

fastapi-typed-errors

English · Русский

PyPI - Version PyPI - Python Version PyPI - Status PyPI - Downloads FastAPI Pydantic v2

GitHub Release GitHub Repo stars GitHub last commit CI Coverage Status Docs

Typed HTTP errors for FastAPI — exact Literal codes in OpenAPI, discriminated oneOf unions on the code field, and a single source of truth: the error class itself.

In plain FastAPI, raise HTTPException(404, "...") buries the error code in a string — clients can't switch on it, OpenAPI has no code type or body schema, and you hand-maintain responses={} on every route. This package makes an error a class: its HTTP status, machine-readable code and response model are declared once and derived automatically, so your error contract is typed, self-documenting, and verifiable in CI.

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]]:
    if item_id == 0:
        raise NotFoundError("No item")
    return Item(item_id=item_id)

The response body is always {"code": "NOT_FOUND", "detail": "No item"}, and OpenAPI gets a 404 with the exact Literal["NOT_FOUND"] code and body model — no manual responses.

Install

pip install fastapi-typed-errors          # core + decorator
pip install "fastapi-typed-errors[cli]"   # + the CI-checker CLI

Requires Python 3.12+, FastAPI ≥ 0.115, Pydantic ≥ 2.9.

How to use it

1. Define errors and register the one handler.

from fastapi import FastAPI
from fastapi_typed_errors import BaseError, handle_base_error

app = FastAPI()
app.add_exception_handler(BaseError, handle_base_error)

2. Declare errors — pick your level of magic:

# a) by hand (core only) — write responses yourself
@app.get("/x", responses={404: {"model": error_models(NotFoundError)}})
def a() -> Item: ...


# b) declared — the marker fills responses for you
router = with_errors(APIRouter())


@router.get("/y")
def b() -> Annotated[Item, Raises[NotFoundError, ForbiddenError]]: ...


# c) automatic — no markers at all; errors are found statically
router = with_errors(APIRouter(), auto=True)


@router.get("/z")
def c(user: Annotated[User, Depends(current_user)]) -> Item:
    raise NotFoundError("...")  # auto -> 404, plus whatever current_user raises

3. Verify the contract in CI. check_raises compares what each route declares against what it can actually raise — in the endpoint and its whole dependency tree:

def test_error_contracts() -> None:
    assert check_raises(app).ok

Or as a command: fastapi-typed-errors check app.main:app (exit 0/1/2).

Why it's cool

  • Exact types in OpenAPI — a precise Literal code per status; several errors on one status become a discriminated oneOf union, so Swagger UI shows a variant picker by code.
  • Single source of truth — status, code and model declared once; the metaclass derives the rest.
  • Zero-boilerplate responses — via the Raises marker or fully automatic auto=True.
  • Static contract checkingcheck_raises catches a raise you forgot to declare (or a dead declaration) before it ships.
  • Non-invasivewith_errors patches the router in place and preserves object identity, so include_router, websockets and app-level decorators keep working natively.
  • Rigorous — fully typed (py.typed), 100% branch-covered, checked with ruff + ty at max strictness.

Documentation

📖 Full documentation — guide, customization (custom envelopes, ABC, bare-string codes), limitations, and an auto-generated API reference. Available in English and Russian.

License

MIT.


uv Ruff ty pytest Material for MkDocs Conventional Commits Semantic Versions

GitHub License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_typed_errors-1.0.0.tar.gz (20.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_typed_errors-1.0.0-py3-none-any.whl (26.8 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_typed_errors-1.0.0.tar.gz.

File metadata

  • Download URL: fastapi_typed_errors-1.0.0.tar.gz
  • Upload date:
  • Size: 20.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fastapi_typed_errors-1.0.0.tar.gz
Algorithm Hash digest
SHA256 833578887e9e77fc88b8412063e813c5face148cf090192cb344b1a4db99210b
MD5 b9ac5199a93732a0e86ae4e1704e2dd0
BLAKE2b-256 79ccfcd568de407155feb093034c3f883da725768dd6f32b7b12c246992ed9cf

See more details on using hashes here.

File details

Details for the file fastapi_typed_errors-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_typed_errors-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 26.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fastapi_typed_errors-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d4f32c26194b28685f95058b12ac93adb6f341300cfc8d1a31a9964973a97ccf
MD5 aace85a5a3484af279eb956fe182b82b
BLAKE2b-256 b9640beb32eb4a2fb542ed68a59fa3984cd93ea9fa97c9748467737b120b06f9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page