
FastAPI
Learn the fundamentals of exception handlers in FastAPI.
Exception handlers allow you to customize how your API responds when errors occur. Instead of returning raw Python exceptions, handlers convert exceptions into properly formatted HTTP responses that clients can understand and process.
In this section, you'll understand:
from fastapi import FastAPI
from fastapi.responses import JSONResponse
app = FastAPI()
class ItemNotFoundError(Exception):
def __init__(self, item_id: int):
self.item_id = item_id
@app.exception_handler(ItemNotFoundError)
async def item_not_found_handler(request, exc):
return JSONResponse(
status_code=404,
content={
"error": "ItemNotFound",
"message": f"Item {exc.item_id} not found"
}
)
@app.get("/items/{item_id}")
async def get_item(item_id: int):
if item_id > 100:
raise ItemNotFoundError(item_id)
return {"id": item_id}from fastapi import FastAPI
from fastapi.responses import JSONResponse
import logging
app = FastAPI()
logger = logging.getLogger(__name__)
class DatabaseError(Exception):
pass
class ValidationError(Exception):
def __init__(self, field: str, message: str):
self.field = field
self.message = message
@app.exception_handler(DatabaseError)
async def db_error_handler(request, exc):
logger.error(f"Database error: {exc}")
return JSONResponse(
status_code=500,
content={
"error": "DatabaseError",
"message": "Database operation failed"
}
)
@app.exception_handler(ValidationError)
async def validation_error_handler(request, exc):
return JSONResponse(
status_code=422,
content={
"error": "ValidationError",
"field": exc.field,
"message": exc.message
}
)
@app.post("/users/")
async def create_user(user: dict):
if not user.get("email"):
raise ValidationError("email", "Email is required")
try:
# Save to database
db.save_user(user)
except Exception as e:
raise DatabaseError("Failed to save user")
return userimport uuid
from datetime import datetime
from typing import Optional
class AppException(Exception):
def __init__(self, code: str, message: str, status_code: int = 400):
self.code = code
self.message = message
self.status_code = status_code
@app.exception_handler(AppException)
async def app_exception_handler(request, exc):
request_id = str(uuid.uuid4())
logger.warning(
f"AppException: {exc.code} | Message: {exc.message} | Request ID: {request_id}"
)
return JSONResponse(
status_code=exc.status_code,
content={
"error": {
"code": exc.code,
"message": exc.message,
"request_id": request_id,
"timestamp": datetime.utcnow().isoformat()
}
}
)
@app.exception_handler(Exception)
async def general_exception_handler(request, exc):
request_id = str(uuid.uuid4())
logger.error(
f"Unhandled exception | Error: {str(exc)} | Request ID: {request_id}",
exc_info=True
)
return JSONResponse(
status_code=500,
content={
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"request_id": request_id
}
}
)Exception handlers are essential for:
Example - Microservices with error handling:
class ServiceUnavailableError(AppException):
def __init__(self, service_name: str):
super().__init__(
code="SERVICE_UNAVAILABLE",
message=f"{service_name} service is temporarily unavailable",
status_code=503
)
class RateLimitError(AppException):
def __init__(self, retry_after: int):
super().__init__(
code="RATE_LIMITED",
message="Too many requests. Please try again later",
status_code=429
)
self.retry_after = retry_after
@app.exception_handler(RateLimitError)
async def rate_limit_handler(request, exc):
return JSONResponse(
status_code=429,
headers={"Retry-After": str(exc.retry_after)},
content={
"error": {
"code": exc.code,
"message": exc.message,
"retry_after": exc.retry_after
}
}
)
@app.get("/payment-status/{transaction_id}")
async def get_payment_status(transaction_id: str):
try:
return payment_service.get_status(transaction_id)
except payment_service.ConnectionError as e:
raise ServiceUnavailableError("PaymentService")Ready to explore more? Check out the advanced section for production patterns and edge cases.
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward