| [ Web Proxy ] |
| Viewing: https://feodor-ra.github.io/fastapi-typed-errors/ | [Back] [Original] |
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 an error is HTTPException(404, "..."). The error code lives in a string, OpenAPI has neither a code type nor a response-body model, and the list of errors a route can raise has to be duplicated by hand into responses={}. Clients can't switch on the code, and the docs drift away from the code fast.
fastapi-typed-errors makes an error a class: the HTTP status, machine-readable code and response model are declared once and derived automatically.
@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}
detail; in OpenAPI the 404 has neither an exact code nor a body schema.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)
responses automatically: a 404 with the exact Literal["NOT_FOUND"] and a {code, detail} body.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)
responses build themselves: the walker finds raise NotFoundError (and errors raised by dependencies) statically. See auto=True.The error response body is always predictable:
And in OpenAPI the route gets one entry per status with an exact code and a body model. Here is how it renders in Swagger UI:
Single source of truth
Status, code and response model are declared once in the error class. The metaclass derives the rest.
Exact types in OpenAPI
Every status gets an exact Literal code; several errors on one status become a discriminated oneOf union on code.
Declared right in the annotation
-> Annotated[Item, Raises[NotFoundError, ForbiddenError]] and responses fill themselves.
CI contract checking
check_raises compares what's declared against what's actually raised in the endpoint and its dependencies.
Auto-fill
with_errors(router, auto=True) finds errors statically and fills responses without a single marker.
Extensible
Your own envelope response model, your own codes (StrEnum or a bare Literal), compatibility with ABC.
Requirements
0.1370.138 versions are excluded see Limitations)| Web Proxy Viewer | New URL | Original Page |