Dependency Injection¶
FastAPI's Depends() system is the backbone of the application. Every service, repository, and cross-cutting concern flows through it.
Database Session¶
from collections.abc import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncSession
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with async_session_maker() as session:
yield session
Repository and Service Dependencies¶
Chain dependencies to build the full layer stack:
from fastapi import Depends
async def get_user_repository(
db: AsyncSession = Depends(get_db),
) -> UserRepository:
return UserRepository(db)
async def get_user_service(
repo: UserRepository = Depends(get_user_repository),
event_bus: EventBus = Depends(get_event_bus),
) -> UserService:
return UserService(repo=repo, event_bus=event_bus)
Routes then declare the service they need:
@router.get("/users/{user_id}", response_model=UserResponse)
async def get_user(
user_id: UUID,
service: UserService = Depends(get_user_service),
) -> UserResponse:
return await service.get_user(user_id)
Parameterized Dependencies¶
Use closures for configurable dependencies like permission checks:
def requires_permission(permission: str):
async def dependency(
current_user: User = Depends(get_current_active_user),
) -> User:
if not current_user.has_permission(permission):
raise ForbiddenError(f"Missing permission: {permission}")
return current_user
return dependency
@router.delete("/users/{user_id}", status_code=204)
async def delete_user(
user_id: UUID,
service: UserService = Depends(get_user_service),
_: User = Depends(requires_permission("users:delete")),
):
await service.delete_user(user_id)
When to Use Depends¶
| Scenario | Use Depends() |
Use direct instantiation |
|---|---|---|
| Database sessions | Yes | Never |
| Repositories and services | Yes | Never |
| Auth / current user | Yes | Never |
| Configuration values | Yes (via Settings) |
For constants |
| Utility functions with no I/O | No | Yes |
See Also¶
- Design Patterns -- Layered architecture and factory patterns that depend on DI
- Configuration Management -- Pydantic Settings injected via Depends