Mental model
FastAPI's dependency injection engine constructs a Directed Acyclic Graph (DAG) of dependencies per HTTP request, solving requirements, managing resource scope, and closing yield generators upon request completion.
Theory
Dependencies declared with Depends(func) can be nested arbitrarily deep. When a dependency uses yield instead of return, FastAPI executes code before yield prior to route handler execution, injects the yielded value, and executes code after yield during response cleanup (even if an exception occurs).
Alternatives and trade-offs
Manual dependency instantiation leads to code duplication and tight coupling. FastAPI's app.dependency_overrides allows swapping real databases for in-memory mocks during Pytest runs seamlessly.
Failure modes and misconceptions
- Leaking resources without
finally: Failing to wrapyieldcleanup intry...finallyleaves database sessions unclosed if route handlers raise uncaught exceptions. - Global state mutation: Modifying global dependency state across concurrent requests causes race conditions.
Decision scenario
Use asynccontextmanager lifespans for global application resource pools (database pools, Redis clients). Use Depends with yield generators for per-request session isolation.
Learning outcomes
- Build composable dependency DAGs in FastAPI routes.
- Implement lifespan context managers for application lifecycle state.
- Swap production dependencies with test doubles via
dependency_overrides.
Trade-offs
FastAPI dependency injection simplifies composition and testing, but complex nested dependency graphs can make execution order harder to trace without clear logging.