
Dependency Injection: Core Concepts
The 'Secret Weapon' of FastAPI. Learn what dependency injection is, why it matters, and how it simplifies your code.
Dependency Injection: Core Concepts
If Pydantic is the "Engine" of FastAPI, Dependency Injection (DI) is the "Circulatory System." It is the feature that allows you to write modular, testable, and clean code that handles things like database connections and user authentication with zero repetition.
In this lesson, we demystify what DI is and why FastAPI's implementation is world-class.
1. What is Dependency Injection?
In software terms, a Dependency is something your code needs to work. For example, a function that saves a user needs a Database Connection.
The "Old" Way (Hard-Coding):
def create_user():
db = MyDatabaseDriver("url") # Dependency is hard-coded!
db.save(user)
The problem: If you want to change the database or use a "Mock" database for testing, you have to edit every single function.
The "FastAPI" Way (Injection):
You define what you need in the function argument, and FastAPI "Injects" it for you.
from fastapi import Depends
def get_db():
# Setup logic
return Database()
@app.post("/users")
def create_user(db = Depends(get_db)):
db.save(user)
2. Why Dependency Injection Matters
- Code Reuse: One
get_dbfunction can be used by 100 endpoints. - Testability: When testing, you can easily "Override" the dependency with a fake one without changing your application code.
- Security: You can create dependencies that check if a user is logged in before even running the function logic.
- Database Management: DI allows you to open a database session at the start of a request and automatically close it at the end.
3. Request-Scoped vs. Global
In FastAPI, dependencies are usually Request-Scoped. This means:
- User makes a request.
- FastAPI runs the dependency (e.g., opens a DB connection).
- FastAPI runs your endpoint function (using the connection).
- FastAPI finishes the request and cleans up the dependency (e.g., closes DB connection).
4. The Depends Function
Depends is the helper that tells FastAPI how to resolve a dependency. It takes a single argument: a function (or a class).
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
Visualizing the Injection Flow
graph TD
A["User Request"] --> B["FastAPI Dependency Resolver"]
B --> C["Run get_db()"]
B --> D["Run get_current_user()"]
C & D --> E["Inject into your Function"]
E --> F["Your Business Logic"]
F --> G["Automatic Clean-up (Yield)"]
Summary
- Dependency Injection separates Logic from Resources.
Dependsis the only tool you need to master.- Decoupling makes your app stable and easy to test.
In the next lesson, we’ll look at Common Use Cases (Databases and Auth) to see DI in action.
Exercise: The Logger
Write a simple dependency function called get_logger that just returns a string "LOG: [Request Started]". Then, show how you would "Inject" this into an @app.get("/") endpoint.