FastAPI Production Patterns
FastAPI Production Patterns
FastAPI is my default framework for Python APIs. Here are the patterns I use in every production deployment.
Dependency Injection for Services
FastAPI's Depends() system is more powerful than most people use. I wire all external services (database, LLM providers, cache) through dependency injection:
async def get_db() -> AsyncSession:
async with async_session() as session:
yield session
async def get_llm() -> LLMProvider:
return LLMProvider()
@app.post("/query")
async def query(
request: QueryRequest,
db: AsyncSession = Depends(get_db),
llm: LLMProvider = Depends(get_llm),
):
...
This makes testing trivial — just override the dependencies with mocks.
Background Tasks with Lifespan
For long-running AI tasks, I use FastAPI's BackgroundTasks combined with the lifespan pattern for startup/shutdown:
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: initialize connection pools, load models
app.state.model = await load_model()
yield
# Shutdown: clean up resources
await app.state.model.close()
Structured Logging
Don't use print() or basic logging. Use structlog or a JSON-based logger that captures request IDs, latency, and error context. Every log line should be traceable to a specific request.
Database Sessions
Use async sessions with SQLAlchemy 2.0's async engine. Never share sessions across requests. Always use session-per-request pattern with dependency injection.
The combination of these patterns produces APIs that are testable, observable, and maintainable at scale.