⚙️ Dependency Injection in FastAPI — Cleaner, Smarter APIs

Ayesha MughalAyesha Mughal
3 min read

Dependency Injection (DI) is one of FastAPI’s most powerful features. It allows developers to reuse logic, organize code cleanly, and make endpoints modular. In this guide, we’ll explore how DI works in FastAPI with practical examples—ranging from simple functions to advanced class-based patterns.


📌 Why Dependency Injection?

Before diving into code, let’s understand why DI matters:

BenefitDescription
🔁 ReusabilityWrite logic once, inject it wherever needed
🧹 Separation of ConcernsKeep route logic focused on request handling, not shared utilities
🧪 TestabilityEasily mock dependencies in test cases
🗂️ OrganizationBetter code structure and maintainability

🧠 How FastAPI Does It

FastAPI provides a Depends() utility. This tells FastAPI:

“Resolve this value before running the endpoint function.”

You define a dependency function (or class with __call__) and use Depends() to inject its return value into your endpoint.

🔸 Dependencies can:

  • Have parameters of their own

  • Use other dependencies (sub-dependencies)

  • Be reused and cached per request automatically


✅ Setup

uv init fastdca_p1
cd fastdca_p1
uv venv
source .venv/bin/activate
uv add "fastapi[standard]"

Example 1: 🔹 Simple Dependency

from fastapi import FastAPI, Depends
from typing import Annotated

app = FastAPI()

def get_simple_goal():
    return {"goal": "We are building AI Agents Workforce"}

@app.get("/get-simple-goal")
def simple_goal(response: Annotated[dict, Depends(get_simple_goal)]):
    return response

🧩 Use Case: Share a constant or a system status across endpoints.


Example 2: 🔸 Dependency With Parameters

def get_goal(username: str):
    return {"goal": "We are building AI Agents Workforce", "username": username}

@app.get("/get-goal")
def get_my_goal(response: Annotated[dict, Depends(get_goal)]):
    return response

🧩 Use Case: Inject a user context, config value, or filtered data dynamically.


Example 3: 🔐 Dependency Using Query Parameters

from fastapi import Query

def dep_login(username: str = Query(None), password: str = Query(None)):
    if username == "admin" and password == "admin":
        return {"message": "Login Successful"}
    return {"message": "Login Failed"}

@app.get("/signin")
def login_api(user: Annotated[dict, Depends(dep_login)]):
    return user

🧩 Use Case: Lightweight login checks or access control.


Example 4: ⚡ Multiple Dependencies in One Endpoint

def depfunc1(num: int):
    return num + 1

def depfunc2(num: int):
    return num + 2

@app.get("/main/{num}")
def get_main(
    num: int,
    num1: Annotated[int, Depends(depfunc1)],
    num2: Annotated[int, Depends(depfunc2)]
):
    total = num + num1 + num2
    return f"Pakistan {total}"

🧩 Use Case: Compose dynamic logic from small, testable parts.


Example 5: 🏗️ Using Classes as Dependencies

The Data

blogs = {
    "1": "Generative AI Blog",
    "2": "Machine Learning Blog",
    "3": "Deep Learning Blog"
}

users = {
    "8": "Ahmed",
    "9": "Mohammed"
}

The Class Dependency

from fastapi import HTTPException, status

class GetObjectOr404:
    def __init__(self, model):
        self.model = model

    def __call__(self, id: str):
        obj = self.model.get(id)
        if not obj:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"Object ID {id} not found"
            )
        return obj

Injecting It

blog_dependency = GetObjectOr404(blogs)

@app.get("/blog/{id}")
def get_blog(blog_name: Annotated[str, Depends(blog_dependency)]):
    return blog_name

user_dependency = GetObjectOr404(users)

@app.get("/user/{id}")
def get_user(user_name: Annotated[str, Depends(user_dependency)]):
    return user_name

🧩 Use Case: Abstract validation logic, reuse it across routes without repeating code.


🔍 Sub-Dependencies

Yes—dependencies can depend on other dependencies. FastAPI resolves all of them recursively and caches them within the request lifecycle.

🔸 Think of it as a dependency graph:
Each node (function/class) can link to others, and FastAPI handles the execution.


✅ Summary

ConceptExample Usage
Depends(func)Inject a reusable resource or logic
Sub-dependenciesAuth that relies on DB check
Class dependenciesFetch and validate model data
Multiple injectionsCompose logic across helpers

🧪 Testing Tip

FastAPI dependencies can be overridden during tests using app.dependency_overrides[].
This makes your application extremely testable and modular.


Happy coding, lovely minds 💖

Written with 💻, ☕, and too much love by Ayesha Mughal a.k.a MughalSyntax

0
Subscribe to my newsletter

Read articles from Ayesha Mughal directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ayesha Mughal
Ayesha Mughal

💻 CS Student | Python & Web Dev Enthusiast 🚀 Exploring Agentic AI | CS50x Certified ✨ Crafting logic with elegance