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

Depends Basics

python
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 params

Code explanation:

  • Depends(common_parameters) runs common_parameters before list_items
  • Return value is injected as params

Use typed model instead of dict for clarity:

python
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 pagination

Database Session Pattern (Preview)

Standard SQLAlchemy session dependency—expanded in SQLAlchemy chapter:

python
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:

  • yield provides value to route, then runs finally after response
  • Ensures session closes even on exceptions

Dependency Chains

Code explanation:

  • get_admin_user depends on get_current_user
  • FastAPI resolves the graph automatically

Full auth in authentication chapter.

Class-Based Dependencies

python
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:

python
router = APIRouter(dependencies=[Depends(verify_api_key)])
 
@router.get("/internal")
def internal():
    return {"ok": True}

Override Dependencies in Tests

Code explanation:

  • dependency_overrides replaces get_db during 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.