Skip to main content

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.
dependency
Callable
The function to execute as a dependency. If None, the parameter type annotation is used.
use_cache
bool
default:"True"
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.
dependency
Callable
The security scheme function to execute
scopes
list[str]
default:"[]"
Required OAuth2 scopes for this endpoint
use_cache
bool
default:"True"
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

Build docs developers (and LLMs) love