In FastAPI, exception handling is crucial to ensure that your API gracefully handles errors and provides meaningful responses to users. FastAPI provides a robust mechanism for catching exceptions and returning custom responses. Here’s a detailed guide on exception handling in FastAPI:
1. Using HTTPException
FastAPI has a built-in HTTPException
class, which you can raise when you need to return a specific HTTP status code along with a message.
Example of HTTPException
:
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
if item_id == 3:
raise HTTPException(status_code=404, detail="Item not found")
return {"item_id": item_id}
In this example, if the user requests item ID 3, the server will return a 404 status with the message "Item not found".
2. Custom Exception Handling
You can define your custom exception classes and handle them using FastAPI’s dependency injection and exception handlers.
Example of Custom Exception:
from fastapi import FastAPI, HTTPException
from typing import Union
app = FastAPI()
class ItemNotFoundException(Exception):
def __init__(self, name: str):
self.name = name
@app.get("/items/{item_name}")
async def get_item(item_name: str):
if item_name == "broken_item":
raise ItemNotFoundException(name=item_name)
return {"item_name": item_name}
Or Simple Override the HttpException as
from fastapi import FastAPI, HTTPException
app = FastAPI()
class ItemNotFoundException(HTTPException):
def __init__(self, item_name: str):
super().__init__(
status_code=404,
detail={
"error_code": "ITEM_NOT_FOUND",
"message": f"'{item_name}' Not Found.",
"redirect": True,
"redirect_to": "product_list"
},
)
@app.get("/items/{item_name}")
async def get_item(item_name: str):
if item_name == "broken_item":
# Raise the custom exception when the item is "broken_item"
raise ItemNotFoundException(item_name=item_name)
return {"item_name": item_name}
3. Global Exception Handlers
FastAPI allows you to register global exception handlers using the @app.exception_handler
decorator.
Example of a Global Exception Handler:
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
# Custom exception
class ItemNotFoundException(Exception):
def __init__(self, name: str):
self.name = name
# Global handler
@app.exception_handler(ItemNotFoundException)
async def item_not_found_exception_handler(request, exc: ItemNotFoundException):
return JSONResponse(
status_code=404,
content={"message": f"Item {exc.name} not found"},
)
@app.get("/items/{item_name}")
async def get_item(item_name: str):
if item_name == "broken_item":
raise ItemNotFoundException(name=item_name)
return {"item_name": item_name}
In this example, the global exception handler will catch any ItemNotFoundException
and return a custom JSON response.
4. Handling Validation Errors
FastAPI automatically raises validation errors when the input data doesn’t match the expected type or format. You can catch and handle these errors using FastAPI’s built-in error handlers.
Example of Validation Error Handling:
from fastapi import FastAPI, Body, HTTPException
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
async def create_item(item: Item):
if item.price < 0:
raise HTTPException(status_code=400, detail="Price must be greater than 0")
return {"name": item.name, "price": item.price}
Here, FastAPI will automatically handle the validation errors if the request body doesn't match the Item
schema.
5. Custom Error Responses
FastAPI also allows you to define custom error responses . You can define a custom exception handler for HTTPException
or specifically for your custom error, and within that handler, you can use the response_model
to structure the error response.
Example of Custom Error Responses:
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
# Define the response model for errors
class ErrorResponse(BaseModel):
detail: str
# Exception handler for HTTPException
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail}
)
@app.get("/error")
async def error_endpoint():
raise HTTPException(status_code=400, detail="Custom error")
In this example, a custom error response is defined.
6. Catch-All Exception Handler
You can also define a catch-all exception handler to catch any unexpected exceptions that are not explicitly handled.
Example of Catch-All Exception Handler:
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(Exception)
async def global_exception_handler(request, exc: Exception):
return JSONResponse(
status_code=500,
content={"message": "An unexpected error occurred","exception":str(exc)},
)
@app.get("/cause_error")
async def cause_error():
raise ValueError("This is an unexpected error!")
7. Handling Database Errors
If you're using a database, you can catch exceptions that are specific to your database (e.g., SQLAlchemy
exceptions). FastAPI allows you to handle these exceptions in the same way as other exceptions.
Example of Handling Database Errors:
from fastapi import FastAPI, HTTPException
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from database import SessionLocal, engine
app = FastAPI()
@app.post("/add_item")
async def add_item(item_name: str, db: Session = Depends(get_db)):
try:
db_item = Item(name=item_name)
db.add(db_item)
db.commit()
return {"message": "Item added"}
except IntegrityError:
db.rollback()
raise HTTPException(status_code=400, detail="Item already exists")
In this example, if there is a database constraint violation (like adding an item that already exists), an IntegrityError
is caught, and a custom HTTP error is returned.
Summary:
- HTTPException: Use this for standard HTTP error responses.
- Custom Exceptions: Define and raise your own custom exceptions.
- Global Handlers: Define custom exception handlers for specific exceptions.
- Validation Errors: Automatically handled by FastAPI for request data validation.
- Catch-All Handlers: Handle all unexpected exceptions globally.
- Database Errors: Handle database-specific errors like
IntegrityError
.