agentbench / data /tech_docs /fastapi_dependencies.md
Nomearod's picture
feat: Day 4 — corpus, ingest script, first 10 golden questions
a152b95

Dependency Injection in FastAPI

FastAPI includes a built-in dependency injection system that allows you to share logic, enforce authentication, manage database connections, and more. Dependencies are declared using Depends() and are resolved automatically for each request.

Basic Dependency

A dependency is any callable (function or class) that FastAPI calls before the route handler:

from fastapi import FastAPI, Depends, Query

app = FastAPI()

async def common_parameters(
    skip: int = Query(default=0, ge=0),
    limit: int = Query(default=100, ge=1, le=1000),
):
    return {"skip": skip, "limit": limit}

@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
    return {"params": commons}

@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
    return {"params": commons}

Both /items/ and /users/ share the same pagination logic. The common_parameters function is called once per request, and its return value is injected into the commons parameter.

Class-Based Dependencies

Classes work as dependencies because calling a class creates an instance (i.e., MyClass() is callable):

class PaginationParams:
    def __init__(
        self,
        skip: int = Query(default=0, ge=0),
        limit: int = Query(default=100, ge=1, le=1000),
    ):
        self.skip = skip
        self.limit = limit

@app.get("/items/")
async def read_items(pagination: PaginationParams = Depends(PaginationParams)):
    return {"skip": pagination.skip, "limit": pagination.limit}

FastAPI provides a shorthand: Depends(PaginationParams) can also be written as Depends() when the type annotation already specifies the class: pagination: PaginationParams = Depends().

Sub-Dependencies

Dependencies can depend on other dependencies, forming a chain that FastAPI resolves automatically:

def query_extractor(q: str | None = None):
    return q

def query_or_default(q: str = Depends(query_extractor)):
    if not q:
        return "default_query"
    return q

@app.get("/items/")
async def read_items(query: str = Depends(query_or_default)):
    return {"query": query}

FastAPI resolves the dependency tree from the leaves up. In this case, query_extractor runs first, then query_or_default receives its result. The maximum depth of the dependency chain is not explicitly limited, but in practice chains deeper than 10 levels indicate a design issue.

Dependencies with Yield (Resource Management)

Use yield in a dependency to run setup code before and cleanup code after the route handler executes. This is ideal for managing database sessions, file handles, or locks:

from sqlalchemy.orm import Session

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/items/")
async def read_items(db: Session = Depends(get_db)):
    items = db.query(Item).all()
    return items

The code before yield runs before the handler, the yielded value is injected as the dependency, and the code after yield runs after the response is sent. The finally block ensures cleanup happens even if an exception occurs. FastAPI supports up to 32 yield dependencies per request by default.

Global Dependencies

Apply dependencies to every route in the application by passing them to the FastAPI constructor:

from fastapi import FastAPI, Depends, Header, HTTPException

async def verify_api_key(x_api_key: str = Header()):
    if x_api_key != "secret-key-123":
        raise HTTPException(status_code=403, detail="Invalid API key")

app = FastAPI(dependencies=[Depends(verify_api_key)])

@app.get("/items/")
async def read_items():
    return [{"item": "Widget"}]

Every route in this application requires a valid X-Api-Key header. You can also scope dependencies to a specific router using APIRouter(dependencies=[...]).

Caching Behavior

By default, if the same dependency is used multiple times within a single request (e.g., both a route and a sub-dependency use Depends(get_db)), FastAPI caches the result and calls the dependency only once. To disable caching and force a fresh call each time, use Depends(get_db, use_cache=False).