FastAPI
FastAPI
Modern async Python web framework. Standard choice for AI/ML APIs and backend services. Built on Starlette (ASGI) + Pydantic. Auto-generates OpenAPI docs.
pip install fastapi uvicorn[standard]
uvicorn main:app --reload # dev server
uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4 # production
Minimal App
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(title="My API", version="1.0.0")
class User(BaseModel):
name: str
email: str
@app.get("/users/{user_id}")
async def get_user(user_id: int) -> User:
return User(name="Alice", email="alice@example.com")
@app.post("/users", status_code=201)
async def create_user(user: User) -> User:
# user is already validated Pydantic model
return user
Visit /docs → interactive Swagger UI. Visit /redoc → ReDoc.
Path, Query, Body Parameters
from fastapi import Query, Path, Body
from typing import Optional
# Path parameter — required
@app.get("/items/{item_id}")
async def get_item(item_id: int = Path(gt=0)): # validation: > 0
...
# Query parameters — optional with default
@app.get("/items")
async def list_items(
skip: int = Query(0, ge=0),
limit: int = Query(10, le=100),
search: Optional[str] = None
):
...
# Request body — Pydantic model
class CreateItem(BaseModel):
name: str
price: float
tags: list[str] = []
@app.post("/items")
async def create_item(item: CreateItem):
...
# Multiple body params
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: CreateItem,
user: User = Body(embed=True) # nest under "user" key in JSON
):
...
Response Models & Status Codes
from fastapi import HTTPException
from fastapi.responses import JSONResponse
class UserResponse(BaseModel):
id: int
name: str
# no password field — response model strips it
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
user = await db.get_user(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user # FastAPI validates against UserResponse automatically
# Custom response
@app.get("/users")
async def list_users() -> list[UserResponse]:
users = await db.list_users()
return users
Dependency Injection
FastAPI's DI system is one of its killer features. Declare dependencies as function parameters.
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
# DB session dependency
async def get_db() -> AsyncSession:
async with SessionLocal() as session:
yield session # cleanup runs after request
# Auth dependency
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
) -> User:
user = await verify_token(token, db)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return user
# Use in route
@app.get("/me")
async def get_me(current_user: User = Depends(get_current_user)):
return current_user
Dependency chains: get_current_user → get_db automatically.
Middleware
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
import time
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["https://myapp.com"],
allow_methods=["*"],
allow_headers=["*"],
)
# Custom middleware
class TimingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
start = time.time()
response = await call_next(request)
duration = time.time() - start
response.headers["X-Process-Time"] = str(duration)
return response
app.add_middleware(TimingMiddleware)
Background Tasks
from fastapi import BackgroundTasks
def send_email(email: str, message: str):
# runs after response is sent
email_client.send(email, message)
@app.post("/register")
async def register(user: CreateUser, background_tasks: BackgroundTasks):
created = await db.create_user(user)
background_tasks.add_task(send_email, user.email, "Welcome!")
return created # response sent immediately, email sends after
Routers — Modular Structure
# routers/users.py
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/")
async def list_users(): ...
@router.post("/")
async def create_user(): ...
# main.py
from routers import users, items
app.include_router(users.router)
app.include_router(items.router, prefix="/api/v1")
Error Handling
from fastapi import Request
from fastapi.responses import JSONResponse
# Custom exception
class AppError(Exception):
def __init__(self, message: str, code: int = 400):
self.message = message
self.code = code
# Global handler
@app.exception_handler(AppError)
async def app_error_handler(request: Request, exc: AppError):
return JSONResponse(
status_code=exc.code,
content={"error": exc.message}
)
# Validation error handler (Pydantic)
from fastapi.exceptions import RequestValidationError
@app.exception_handler(RequestValidationError)
async def validation_handler(request, exc):
return JSONResponse(
status_code=422,
content={"detail": exc.errors(), "body": exc.body}
)
Lifespan Events (startup/shutdown)
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: FastAPI):
# startup
await db.connect()
await redis.connect()
yield
# shutdown
await db.disconnect()
await redis.disconnect()
app = FastAPI(lifespan=lifespan)
Testing FastAPI
from fastapi.testclient import TestClient
def test_get_user():
client = TestClient(app)
response = client.get("/users/1")
assert response.status_code == 200
assert response.json()["name"] == "Alice"
# Async test
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_create_user():
async with AsyncClient(app=app, base_url="http://test") as client:
response = await client.post("/users", json={"name": "Bob", "email": "bob@test.com"})
assert response.status_code == 201
Interview Talking Points
- "FastAPI's DI system is its best feature — you declare what a route needs (DB session, current user, feature flags) and FastAPI wires it up. Clean separation, easy to mock in tests."
- "Pydantic models serve dual purpose: request validation and response serialization. One model definition covers both."
- "FastAPI is async by default — routes that do I/O should be
async def. CPU-bound routes should userun_in_executor."
Related
- [[Python/Libraries/Pydantic]] — data validation
- [[Python/Libraries/Asyncio]] — async/await fundamentals
- [[Python/Language Core/Decorators]] — FastAPI uses decorators heavily
- [[API Gateway]] — API design principles