09 Dependency Injection
title: Dependency Injection in FastAPI REST APIs weight: 19 date: 2026-06-28 lastmod: 2026-06-28 description: Master FastAPI dependency injection with Depends, reusable dependencies for auth, database sessions, pagination, and dependency hierarchies for clean architecture. tags: [api-development, fastapi]
FastAPI dependency injection uses the Depends function to declare dependencies in path operation parameters, automatically resolving reusable components like authentication, database sessions, pagination, and configuration.
```mermaid
flowchart TD
A[Route Handler] --> B[Dependency 1]
A --> C[Dependency 2]
B --> D[Auth Check]
C --> E[Database Session]
D --> F[User Object]
E --> G[DB Connection]
A --> H[Response]
style A fill:#e1f5fe
style B fill:#fff9c4
style C fill:#fff9c4
style F fill:#c8e6c9
style G fill:#c8e6c9
Dependencies are callable functions that return values. FastAPI calls them automatically and injects the results into the route handler. Dependencies can have their own dependencies (nesting). Cacheing means dependencies are called once per request even if used multiple times.
Think of dependency injection like a power strip. Each appliance (route handler) plugs into the strip and gets electricity (database connection, auth info). The power strip manages the flow. If two appliances need electricity, they share from the same source.
Example: Basic Dependencies
from fastapi import FastAPI, Depends, Header, HTTPException
from typing import Optional
app = FastAPI()
# Simple dependency
def get_pagination(page: int = 1, limit: int = 10):
return {"page": page, "limit": limit, "skip": (page - 1) * limit}
# Dependency with validation
def verify_token(authorization: Optional[str] = Header(None)):
if not authorization:
raise HTTPException(status_code=401, detail="No auth header")
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid auth format")
token = authorization.replace("Bearer ", "")
if token != "valid-token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"user_id": 42, "role": "admin"}
@app.get("/api/items")
def list_items(
pagination: dict = Depends(get_pagination),
user: dict = Depends(verify_token)
):
return {
"user": user,
"pagination": pagination,
"items": ["item1", "item2"]
}
Example: Database Session Dependency
from fastapi import FastAPI, Depends
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Dependency that provides database session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@app.get("/api/users")
def list_users(db: Session = Depends(get_db)):
users = db.query(UserModel).all()
return {"users": users}
@app.post("/api/users", status_code=201)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = UserModel(**user.model_dump())
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
Example: Dependency with Sub-dependencies
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
app = FastAPI()
class PaginationParams(BaseModel):
page: int = 1
limit: int = 10
# Sub-dependency
def get_pagination(page: int = 1, limit: int = 10):
return PaginationParams(page=page, limit=limit)
# Reusable auth dependency
async def get_current_user(token: str = Depends(verify_token)):
return token
# Auth with role check
def require_admin(user: dict = Depends(get_current_user)):
if user["role"] != "admin":
raise HTTPException(status_code=403, detail="Admin access required")
return user
# Composite dependency
async def get_filtered_query(
db: Session = Depends(get_db),
pagination: PaginationParams = Depends(get_pagination),
user: dict = Depends(get_current_user)
):
return {
"db": db,
"page": pagination.page,
"limit": pagination.limit,
"user_id": user["user_id"]
}
@app.get("/api/admin/users")
def admin_list_users(ctx: dict = Depends(get_filtered_query)):
# ctx has db, page, limit, user_id
return {"context": ctx}
Common Mistakes
- Not using Depends() — Declaring a dependency as a parameter type without Depends() treats it as a query parameter, not a dependency.
- Creating new instances for each request — Dependencies that create database connections should use yield to clean up. Resource leaks cause server crashes.
- Mixing sync and async dependencies incorrectly — FastAPI handles both, but async dependencies can only use async sub-dependencies.
- Not caching dependencies — FastAPI's Depends caches results per request. Repeated Depends(same_func) calls the dependency once. Use this rather than storing results manually.
- Overcomplicating dependency chains — Deeply nested dependencies with side effects are hard to debug. Keep dependencies simple and focused.
Practice Questions
- What is the purpose of Depends() in FastAPI?
- How do you create a dependency that cleans up resources after use?
- Can dependencies have sub-dependencies?
- How does FastAPI cache dependency results per request?
- Challenge: Build a dependency injection system for a blog API with dependencies for: authentication (JWT verify), authorization (check role), database session, pagination, and query filters. Each endpoint should compose the dependencies it needs.
FAQ
Mini Project
Create a dependency injection system for a payment API. Include dependencies for: authentication (API key validation), merchant verification (find merchant by API key), request signing (verify HMAC signature), idempotency (check idempotency key), pagination, and database session. Wire them together in payment endpoints.
What's Next
Now learn about middleware in Building REST APIs with FastAPI.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro