Building Scalable APIs with FastAPI
January 12, 2026
FastAPI has improved the game for web development by leveraging type hints and asynchronous programming. Being fast to write and run, most of the boilerplate is generated as you go.
Below is a modern API setup, broken down into the key layers you need for a live application.
1. Data Models (Pydantic)
FastAPI uses Pydantic to define how data should look. This automatically validates incoming requests and formats outgoing responses.
userSchema.py
from pydantic import BaseModel, EmailStr
class UserCreate(BaseModel):
username: str
email: EmailStr
password: str
class UserResponse(BaseModel):
id: int
username: str
is_active: bool = True
class Config:
from_attributes = True
By using Schemas, the application never has to deal with dirty data.
schemaValidation.py
from pydantic import Field
class Item(BaseModel):
name: str = Field(..., example="Gaming Laptop")
price: float = Field(..., gt=0) # Must be greater than 0
tax: float | None = None
description: str | None = None
2. Dependency Injection
FastAPI’s innate dependency system is the best way to manage shared resources like database sessions or authentication logic.
DatabaseSession.py
from fastapi import Depends
async def get_db_session():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/items/")
async def read_items(db = Depends(get_db_session)):
return db.query(Item).all()
AuthMiddleware.py
from fastapi import Header, HTTPException
async def verify_token(x_token: str = Header(...)):
if x_token != "super-secret-token":
raise HTTPException(status_code=400, detail="Invalid Token")
return x_token
Keeps endpoints clean and easy to debug.
3. Organized Routing (APIRouter)
APIRouter allows you to split your API into logical modules.
UserRoutes.py
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/")
async def get_users():
return [{"username": "dev_user"}]
@router.post("/create")
async def create_user(user: UserCreate):
return {"message": "User created"}
Main.py
from fastapi import FastAPI
from routers import users, items
app = FastAPI(title="My Pro API")
app.include_router(users.router)
app.include_router(items.router)
Routing helps maintain a clear hierarchy and allows different team members to work on different resources simultaneously.
4. Exception Handling
You can define global error handlers that return defined json error responses:
ErrorHandler.py
from fastapi import Request
from fastapi.responses import JSONResponse
class CustomAppError(Exception):
def __init__(self, name: str):
self.name = name
@app.exception_handler(CustomAppError)
async def custom_handler(request: Request, exc: CustomAppError):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} happened."},
)
ValidationOverride.py
@app.get("/trigger-error")
async def trigger():
raise CustomAppError(name="Database Timeout")
With centralized error handling all API users will receive helpful messages on error. Using swagger then makes the documentation for you.