← Back to FastAPI map
FastAPI · Architecture

Dependencies

Depends() for shared setup, yield when something must be cleaned up afterwards, and where to attach each one.

DI

Overview

This is FastAPI's main tool for sharing code between routes. A dependency is just a function or class. FastAPI fills in its arguments the same way it fills in a route's: from the path, the query string, the headers, the body, or other dependencies. Writing Depends(get_db) or Depends(get_current_user) keeps setup and login checks out of your route functions, and lets tests swap each piece out.

Key concepts

Dependency graph
Dependencies can depend on other dependencies. FastAPI resolves the whole graph and, within one request, runs each dependency once and shares its result.
yield dependencies
Code before yield runs before the handler; code after yield runs once the handler has finished - the natural place to close a session or release a lock.
Scope
Attach a dependency to one parameter, to a route with dependencies=[...], to a whole router, or to the entire app.
Class dependencies
A class works as a dependency because calling it creates it; the parameters of __init__ become request parameters.
dependency_overrides
Replaces any dependency with another callable - the key to testing without a real database or auth server.

Best practices

  • Keep dependencies small and single-purpose - get_db, get_current_user, require_role - and compose them.
  • Use yield dependencies for anything that needs cleanup, so it happens even when the handler raises.
  • Define Annotated aliases such as CurrentUser = Annotated[User, Depends(get_current_user)] to avoid repeating Depends everywhere.

Dependency injection

Depends() - the core concept

Core
Request arrives→Depends() resolved→Route handler called→Response returned
from fastapi import Depends, HTTPException, Query # Simple dependency function def get_query_params( skip: int = 0, limit: int = 20 ) -> dict: return {"skip": skip, "limit": limit} @app.get("/items") async def list_items( params: dict = Depends(get_query_params) ): return params # {"skip": 0, "limit": 20} # Class-based dependency (stateful) class Pagination: def __init__(self, page: int = 1, per_page: int = Query(20, le=100)): self.page = page self.per_page = per_page self.skip = (page - 1) * per_page @app.get("/posts") async def list_posts( pagination: Pagination = Depends(Pagination) ): return {"skip": pagination.skip, "per_page": pagination.per_page} # Chained dependencies async def get_db(): async with SessionLocal() as session: yield session async def get_current_user( token: str = Depends(oauth2_scheme), db = Depends(get_db) # deps can depend on deps ): return await validate_token(token, db)

Tip: Within one request, a dependency used in several places runs once and its result is shared - if the route and get_current_user both depend on get_db, they get the same session.

Yield dependencies - resource cleanup

Yield
# Yield deps: code before yield = setup, after = teardown async def get_db(): session = SessionLocal() try: yield session # route handler runs here await session.commit() except Exception: await session.rollback() raise finally: await session.close() # Redis connection (redis-py; aioredis was merged into it) import redis.asyncio as redis async def get_redis(): client = redis.from_url("redis://localhost") try: yield client finally: await client.aclose()

Tip: For a connection used on every request, create one client in lifespan and share it; a per-request dependency like this suits resources that really are per-request, such as a DB session.

Router-level and global dependencies

Scope
# Apply to a specific route @app.get("/private", dependencies=[Depends(verify_token)]) async def private(): return {"secret": True} # Apply to entire router (all routes auth-gated) router = APIRouter( prefix="/admin", dependencies=[Depends(require_admin)] ) # Apply to entire app app = FastAPI(dependencies=[Depends(rate_limiter)])

Comments

Sign in to leave a comment. Your name and photo come from Google; nothing else is shared.

Loading comments...