Home/Learn/FastAPI/Depends — Dependency Injection Basics

Depends — Dependency Injection Basics

Intermediate
Dependency Injection

Depends(fn) tells FastAPI: run fn first (resolving ITS parameters the same way) and hand me the result. Shared logic — pagination, auth, DB sessions — becomes declared-once, injected-everywhere.

Overview

Dependency injection is FastAPI's signature feature and the reason large codebases stay clean. A dependency is any callable; declaring a parameter as Depends(get_thing) makes FastAPI call it before your endpoint — and because dependency parameters are resolved with the exact same rules (query, path, body, or further Depends), dependencies compose into trees. The classic first use is shared pagination parameters: declare page/size validation once, inject into twenty list endpoints. Within a single request, a dependency used in multiple places runs once and its result is cached — so five things asking for the current user trigger one lookup. This chapter is the mechanism; the next two are the patterns built on it.

The Mechanism — Callables Resolved Before You

A dependency's own parameters bind from the request (query params here). The endpoint receives the return value. Twenty list endpoints, one definition of pagination — change the max page size in one place.

Declare pagination once; every list endpoint inherits it
from typing import Annotated
from fastapi import Depends, FastAPI, Query

app = FastAPI()

# A dependency is just a function — its params bind like any endpoint's
def pagination(
    page: int = Query(default=1, ge=1),
    size: int = Query(default=20, ge=1, le=100),
) -> dict:
    return {"offset": (page - 1) * size, "limit": size}

# Annotated alias — define once, reuse as a type (modern style)
Pagination = Annotated[dict, Depends(pagination)]

@app.get("/students")
def list_students(p: Pagination):
    return {"slice": f"students[{p['offset']}:{p['offset'] + p['limit']}]"}

@app.get("/drives")
def list_drives(p: Pagination):            # same rules, zero duplication
    return {"slice": f"drives[{p['offset']}:{p['offset'] + p['limit']}]"}

# GET /students?page=3&size=50 → {"slice": "students[100:150]"}
# GET /students?size=500       → 422 (le=100) — enforced EVERYWHERE at once

# /docs shows page & size on both endpoints — dependencies are documented too

Sub-Dependencies and Per-Request Caching

Dependencies can depend on dependencies — FastAPI resolves the tree. Within one request each node runs once (result cached), so a chain that needs the current user three times hits the lookup once.

Trees of Depends, each node executed once per request
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException

app = FastAPI()
CALLS = {"user_lookups": 0}

def get_token(authorization: str | None = Header(default=None)) -> str:
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(401, "missing bearer token")
    return authorization.removeprefix("Bearer ")

def get_current_user(token: Annotated[str, Depends(get_token)]) -> dict:
    CALLS["user_lookups"] += 1                    # prove the caching
    return {"id": 7, "name": "Asha", "role": "tpo"}   # (JWT decode → Auth chapter)

def get_user_college(user: Annotated[dict, Depends(get_current_user)]) -> str:
    return "COEP Pune"

@app.get("/dashboard")
def dashboard(
    user: Annotated[dict, Depends(get_current_user)],      # needs user
    college: Annotated[str, Depends(get_user_college)],    # ALSO needs user
):
    return {"user": user["name"], "college": college,
            "lookups_this_request": CALLS["user_lookups"]}
# → lookups_this_request: 1 — get_current_user ran ONCE, result reused
#   (opt out per dependency with Depends(fn, use_cache=False))

# The tree FastAPI resolved:
#   dashboard ── get_current_user ── get_token ── Header
#            └── get_user_college ── get_current_user (cache hit)

Key Points to Remember

  • 1Depends(fn): fn runs first, its params bind from the request, you get the result
  • 2Annotated[T, Depends(fn)] aliases make dependencies reusable one-liners
  • 3Dependencies nest into trees; FastAPI resolves the whole graph
  • 4Per-request caching: the same dependency runs once per request by default

Interview Questions

Sign in to ask Aria
1

Explain FastAPI's Depends to someone who knows Spring — what maps to what?

MediumAmazon
2

Five dependencies in one request all need the current user — how many DB lookups happen and why?

MediumCRED
3

When would you pass use_cache=False to a dependency?

HardUber

Ask Aria about Depends — Dependency Injection Basics

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…