| name | fastapi-backend |
| description | FastAPI best practices for building production Python backends. Use when building REST APIs, async endpoints, Pydantic models, dependency injection, middleware, or any FastAPI server. |
FastAPI Backend Patterns
Project Structure
app/
main.py # FastAPI app, lifespan, middleware
config.py # Pydantic Settings, env vars
models/ # SQLAlchemy ORM models
schemas/ # Pydantic request/response schemas
routers/ # APIRouter per domain (auth, users, posts)
services/ # Business logic (no DB or HTTP here)
deps.py # Shared dependencies (get_db, get_current_user)
database.py # Engine, SessionLocal, Base
Core Patterns
App setup with lifespan
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
await database.connect()
yield
await database.disconnect()
app = FastAPI(lifespan=lifespan)
Dependency injection
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
) -> User:
...
Router pattern
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
user = await db.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
Error handling
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
return JSONResponse(status_code=400, content={"detail": str(exc)})
Pydantic schemas
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=8)
name: str = Field(max_length=100)
class UserResponse(BaseModel):
id: int
email: str
name: str
model_config = ConfigDict(from_attributes=True)
Rules
- Always use async def for endpoints
- Validate ALL input with Pydantic (never trust raw dicts)
- Use HTTPException with specific status codes (not 500 for everything)
- Never put business logic in route handlers — use service layer
- Use response_model to control what's returned (never expose passwords)
- Add CORS middleware for browser clients
- Use Depends() for database sessions — never create sessions manually