FastAPI: From Basics to Production · Building Real APIs
Consistent Error Handling
Return predictable error responses with HTTPException and custom handlers.
Raise HTTPException for expected HTTP errors. For domain errors, raise your own exceptions in services (e.g., NotFound, Conflict) and map them to responses with @app.exception_handler, so services stay HTTP-agnostic. Customize the 422 validation response if clients expect a specific format, and add a catch-all handler that logs unexpected errors with a request ID and returns a generic 500.
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
class DomainError(Exception):
status_code = 400
code = "domain_error"
class NotFound(DomainError):
status_code = 404
code = "not_found"
class Conflict(DomainError):
status_code = 409
code = "conflict"
@app.exception_handler(DomainError)
async def domain_error_handler(request: Request, exc: DomainError) -> JSONResponse:
return JSONResponse(status_code=exc.status_code, content={"code": exc.code, "detail": str(exc)})
@app.exception_handler(Exception)
async def unhandled(request: Request, exc: Exception) -> JSONResponse:
logger.exception("unhandled error", extra={"path": request.url.path})
return JSONResponse(status_code=500, content={"code": "internal_error", "detail": "Something went wrong"})
Common pitfalls
- Leaking stack traces or SQL errors in responses.
- Services raising HTTPException (couples domain to HTTP).
- Inconsistent error shapes between endpoints.
Key points
- Domain exceptions + handlers
- Consistent error envelope
- Log unexpected errors; return generic 500s
Further reading: FastAPI: Handling errors
Go deeper: FastAPI and Starlette: Middleware, Exceptions and Dependencies in the Request Lifecycle course traces this step of the request, with a production bug and a runnable simulation.
Practice questions
Why map domain exceptions to HTTP in handlers instead of raising HTTPException in services?
Answer
Services stay reusable outside HTTP (jobs, CLI), and the HTTP mapping is centralized and consistent.
What status does FastAPI return for request validation errors by default?
Answer
422 Unprocessable Entity, with a detail list describing each invalid field's location and message.
Open in the app to mark lessons complete, take notes and track your progress.