Overview
FastrAPI’s dependency injection system allows you to share logic across route handlers, reduce code duplication, and create reusable components. Dependencies are functions that are executed before your route handler and their results are injected as parameters.
Depends() function
The Depends() function declares a dependency that should be executed and injected into your route handler.
The function to execute as a dependency. If None, the parameter type annotation is used.
Whether to cache the result of the dependency. If True, the dependency is only executed once per request even if used multiple times.
from fastrapi import FastrAPI, Depends
app = FastrAPI()
def get_db():
return {"connection": "database"}
@app.get("/users")
def get_users(db = Depends(get_db)):
return {"db": db, "users": []}
Basic usage
Simple dependency
Create a dependency function and inject it using Depends():
from fastrapi import FastrAPI, Depends
app = FastrAPI()
def get_current_user():
return {"user_id": 42, "username": "john"}
@app.get("/profile")
def get_profile(user = Depends(get_current_user)):
return {"profile": user}
Async dependencies
Dependencies can be async functions:
async def get_database():
# Simulate async database connection
await asyncio.sleep(0.1)
return {"connection": "active"}
@app.get("/data")
async def get_data(db = Depends(get_database)):
return {"data": "from database", "db": db}
Class-based dependencies
Use classes as dependencies for more complex logic:
class DatabaseConnection:
def __init__(self):
self.connection = "postgresql://localhost"
def query(self, sql: str):
return f"Executing: {sql}"
@app.get("/query")
def run_query(db: DatabaseConnection = Depends()):
result = db.query("SELECT * FROM users")
return {"result": result}
Sub-dependencies
Dependencies can depend on other dependencies, creating a dependency tree:
def get_db():
return {"connection": "active"}
def get_current_user(db = Depends(get_db)):
# Uses the db dependency
return {"user_id": 1, "db": db}
def get_user_permissions(user = Depends(get_current_user)):
# Uses the user dependency, which uses the db dependency
return {"user": user, "permissions": ["read", "write"]}
@app.get("/permissions")
def check_permissions(perms = Depends(get_user_permissions)):
return perms
Caching
Default caching behavior
By default, dependencies are cached per request. If the same dependency is used multiple times, it’s only executed once:
call_count = 0
def get_db():
global call_count
call_count += 1
print(f"get_db called {call_count} times")
return {"connection": "active"}
@app.get("/cached")
def cached_example(
db1 = Depends(get_db),
db2 = Depends(get_db), # Same dependency, uses cached result
):
# get_db is only called once
return {"db1": db1, "db2": db2}
Disable caching
Set use_cache=False to execute the dependency every time:
def get_timestamp():
return {"timestamp": time.time()}
@app.get("/uncached")
def uncached_example(
time1 = Depends(get_timestamp, use_cache=False),
time2 = Depends(get_timestamp, use_cache=False),
):
# get_timestamp is called twice, results may differ
return {"time1": time1, "time2": time2}
Dependency injection with parameters
Dependencies can access request parameters (path, query, etc.):
from fastrapi import FastrAPI, Depends, Query
def pagination(skip: int = Query(0), limit: int = Query(10)):
return {"skip": skip, "limit": limit}
@app.get("/items")
def get_items(page = Depends(pagination)):
return {"items": [], "pagination": page}
# Usage: GET /items?skip=20&limit=50
Authentication example
from fastrapi import FastrAPI, Depends, Header, HTTPException
app = FastrAPI()
def verify_token(authorization: str = Header(None)):
if not authorization:
raise HTTPException(status_code=401, detail="Missing token")
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid token format")
token = authorization[7:] # Remove "Bearer " prefix
# Verify token (simplified)
if token != "secret-token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"user_id": 1, "username": "john"}
@app.get("/protected")
def protected_route(user = Depends(verify_token)):
return {"message": f"Hello, {user['username']}!"}
# Usage: GET /protected with Header: Authorization: Bearer secret-token
Database connection example
from typing import Generator
class Database:
def __init__(self, connection_string: str):
self.connection_string = connection_string
self.connected = False
def connect(self):
print(f"Connecting to {self.connection_string}")
self.connected = True
def disconnect(self):
print("Disconnecting from database")
self.connected = False
def query(self, sql: str):
if not self.connected:
raise Exception("Not connected")
return f"Results for: {sql}"
def get_db() -> Generator:
db = Database("postgresql://localhost/mydb")
try:
db.connect()
yield db
finally:
db.disconnect()
@app.get("/users/{user_id}")
def get_user(user_id: int, db = Depends(get_db)):
result = db.query(f"SELECT * FROM users WHERE id = {user_id}")
return {"result": result}
Combining with other features
Dependencies with Request object
from fastrapi import Request
def get_client_info(request: Request):
return {
"client_ip": request.client.host,
"user_agent": request.headers.get("user-agent"),
}
@app.get("/info")
def client_info(info = Depends(get_client_info)):
return info
Dependencies with BackgroundTasks
from fastrapi import BackgroundTasks
def get_logger(background_tasks: BackgroundTasks):
def log(message: str):
background_tasks.add_task(write_log, message)
return log
@app.post("/action")
def perform_action(logger = Depends(get_logger)):
logger("Action performed")
return {"status": "success"}
Security()
The Security() function is a specialized dependency for implementing authentication and authorization with OAuth2 scopes.
The security scheme function to execute
Required OAuth2 scopes for this endpoint
Whether to cache the result of the security dependency
Basic authentication example
from fastrapi import FastrAPI, Security, HTTPException
app = FastrAPI()
def verify_token(token: str = Header(..., alias="Authorization")):
if not token.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid authentication")
token_value = token.replace("Bearer ", "")
if token_value != "secret-token":
raise HTTPException(status_code=401, detail="Invalid token")
return {"user_id": 123, "username": "john"}
@app.get("/protected")
def protected_route(user = Security(verify_token)):
return {"message": f"Hello {user['username']}"}
OAuth2 scopes example
from fastrapi import FastrAPI, Security, HTTPException
app = FastrAPI()
def verify_scopes(
token: str = Header(..., alias="Authorization"),
required_scopes: list[str] = []
):
# Verify token and extract scopes
user_scopes = ["read:users", "write:users"]
for scope in required_scopes:
if scope not in user_scopes:
raise HTTPException(
status_code=403,
detail=f"Missing required scope: {scope}"
)
return {"user_id": 123, "scopes": user_scopes}
@app.get("/users")
def list_users(user = Security(verify_scopes, scopes=["read:users"])):
return {"users": []}
@app.post("/users")
def create_user(user = Security(verify_scopes, scopes=["write:users"])):
return {"created": True}
Best practices
Keep dependencies focused
Each dependency should have a single, well-defined purpose:
# Good: Focused dependencies
def get_db():
return Database()
def get_current_user(db = Depends(get_db)):
return db.query("current_user")
# Avoid: Doing too much in one dependency
def get_everything():
db = Database()
user = db.query("current_user")
permissions = db.query("permissions")
settings = db.query("settings")
return {"db": db, "user": user, "permissions": permissions, "settings": settings}
Use type hints
Type hints improve IDE support and documentation:
def get_db() -> Database:
return Database()
def get_user(db: Database = Depends(get_db)) -> User:
return User.from_db(db)
Reuse dependencies
Create a dependencies module for commonly used dependencies:
# dependencies.py
def get_db():
return Database()
def get_current_user(db = Depends(get_db)):
return User.from_db(db)
# routes.py
from dependencies import get_db, get_current_user
@app.get("/users")
def list_users(db = Depends(get_db)):
return db.query("users")
@app.get("/profile")
def get_profile(user = Depends(get_current_user)):
return user