⚙️ Dependency Injection in FastAPI — Cleaner, Smarter APIs


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:
Benefit | Description |
🔁 Reusability | Write logic once, inject it wherever needed |
🧹 Separation of Concerns | Keep route logic focused on request handling, not shared utilities |
🧪 Testability | Easily mock dependencies in test cases |
🗂️ Organization | Better 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
Concept | Example Usage |
Depends(func) | Inject a reusable resource or logic |
Sub-dependencies | Auth that relies on DB check |
Class dependencies | Fetch and validate model data |
Multiple injections | Compose 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 ✨
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