Dependency Injection
Introduction
Dependency injection in FastAPI means declaring what a route needs—database session, current user, settings—and letting the framework provide it via Depends(). You write reusable components once and compose them across endpoints, with easy overrides in tests.
Prerequisites
- APIRouter and Project Structure
- Understanding of Python
yieldgenerators (helpful)
Depends Basics
from fastapi import Depends, FastAPI
app = FastAPI()
def common_parameters(q: str | None = None, skip: int = 0, limit: int = 10):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items")
def list_items(params: dict = Depends(common_parameters)):
return paramsCode explanation:
Depends(common_parameters)runscommon_parametersbeforelist_items- Return value is injected as
params
Use typed model instead of dict for clarity:
from pydantic import BaseModel
class Pagination(BaseModel):
skip: int = 0
limit: int = 10
def get_pagination(skip: int = 0, limit: int = 10) -> Pagination:
return Pagination(skip=skip, limit=limit)
@app.get("/items")
def list_items(pagination: Pagination = Depends(get_pagination)):
return paginationDatabase Session Pattern (Preview)
Standard SQLAlchemy session dependency—expanded in SQLAlchemy chapter:
from sqlalchemy.orm import Session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/users/{user_id}")
def read_user(user_id: int, db: Session = Depends(get_db)):
return {"user_id": user_id, "db": "connected"}Code explanation:
yieldprovides value to route, then runsfinallyafter response- Ensures session closes even on exceptions
Dependency Chains
Code explanation:
get_admin_userdepends onget_current_user- FastAPI resolves the graph automatically
Full auth in authentication chapter.
Class-Based Dependencies
class Paginator:
def __init__(self, skip: int = 0, limit: int = 10):
self.skip = skip
self.limit = limit
@app.get("/items")
def list_items(p: Paginator = Depends()):
return {"skip": p.skip, "limit": p.limit}Depends() with no argument treats the class as callable dependency.
Router-Level Dependencies
Apply to every route on a router:
router = APIRouter(dependencies=[Depends(verify_api_key)])
@router.get("/internal")
def internal():
return {"ok": True}Override Dependencies in Tests
Code explanation:
dependency_overridesreplacesget_dbduring tests- Clear overrides after tests to avoid leakage
See testing chapter.
Depends vs Global State
Avoid storing request-specific data in module-level globals. Use Depends, Request object, or contextvars.
Warning
Do Not Share Mutable Global DB Session
Each request needs its own session—always yield a new session per call.
Compare With Flask
Flask uses g, manual calls, or extensions. FastAPI makes dependencies explicit in the signature—better for typing and tests.
FAQ
Depends in parameter default only?
Yes—db: Session = Depends(get_db) is required pattern.
Cache dependency result per request?
FastAPI caches same dependency within one request—multiple Depends(get_db) share one session per request.
Async dependencies?
async def get_db() supported—match async routes when using async drivers.
Optional auth?
Return User | None from dependency; route checks if user is None.
Import oauth2_scheme early?
Comes with OAuth2PasswordBearer in JWT chapter—placeholder HTTPBearer works similarly.
Performance overhead?
Minimal—avoid heavy work inside dependencies; cache settings with lru_cache.