Dependency Injection is a design pattern that allows you to provide external dependencies to functions rather than having them create those dependencies internally. FastAPI's dependency injection system is one of its most powerful features, enabling clean, testable, and reusable code.
Why Use Dependency Injection?
Instead of hardcoding database connections, authentication logic, or configuration inside your route handlers, you extract these concerns into separate functions called "dependencies." This makes your code more modular, easier to test, and follows the Single Responsibility Principle.
How FastAPI Dependencies Work
Dependencies in FastAPI are just functions that return values. You use the Depends() function to tell FastAPI to call your dependency function and inject its result into your route handler. FastAPI automatically handles calling the dependency, caching results when appropriate, and handling any errors.
Dependency Composition
One of the most powerful aspects is that dependencies can depend on other dependencies. For example, an authentication dependency might depend on a database dependency to look up user information. FastAPI resolves this dependency tree automatically.
Common Use Cases
Dependencies are perfect for:
This pattern promotes code reuse since the same dependency can be used across multiple endpoints. It also makes testing easier because you can override dependencies with mock implementations during testing.
1from fastapi import FastAPI, Depends
2
3app = FastAPI()
4
5# Simple dependency
6def get_settings():
7 return {"debug": True, "max_items": 100}
8
9# Dependency that depends on another dependency
10def get_db_config(settings: dict = Depends(get_settings)):
11 return f"db://localhost/{settings['debug']}"
12
13@app.get("/items")
14def read_items(config: str = Depends(get_db_config)):
15 return {"database": config, "items": []}
16
17@app.get("/health")
18def health_check(settings: dict = Depends(get_settings)):
19 return {"status": "ok", "debug_mode": settings["debug"]}