WebDev Portfolio

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.