Introduction to Dependencies
Dependency Injection in FastAPI allows you to share logic across multiple path operations, manage database connections, and enforce security requirements without duplicating code. By using the Depends class, you can define requirements that FastAPI will resolve before executing your path operation function.
In this tutorial, you will build a system that handles common query parameters and validates security tokens using reusable dependencies.
Prerequisites
To follow this tutorial, you need FastAPI installed:
pip install fastapi
Create a Basic Function Dependency
When multiple path operations require the same set of query parameters, you can extract that logic into a single function.
Create a file named main.py:
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
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: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
In this example, common_parameters is a dependency. By using Annotated[dict, Depends(common_parameters)], you tell FastAPI that before running the path operation, it must first call common_parameters with the relevant request data and pass the result to the commons parameter.
Use a Class as a Dependency
For more complex logic or when you want to group related data, you can use a class. FastAPI will instantiate the class using its __init__ method as the dependency function.
Update your main.py:
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
return commons
FastAPI detects that CommonQueryParams is a class and calls it. The instance created is then passed to your path operation. This allows you to use type hints like commons.q or commons.skip with full editor support.
Create Sub-dependencies
Dependencies can depend on other dependencies, allowing you to build a tree of requirements.
from typing import Annotated
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: str | None = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[str | None, Cookie()] = None,
):
if not q:
return last_query
return q
@app.get("/items/")
async def read_query(
query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
Here, query_or_cookie_extractor depends on query_extractor. When a request hits /items/, FastAPI first resolves query_extractor, then passes its result to query_or_cookie_extractor, and finally passes that result to read_query.
Add Dependencies to Decorators
Sometimes you need a dependency to run for its side effects (like validation or logging) without needing its return value in your function. You can add these to the dependencies list in the route decorator.
from typing import Annotated
from fastapi import Depends, FastAPI, Header, HTTPException
app = FastAPI()
async def verify_token(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
@app.get("/items/", dependencies=[Depends(verify_token)])
async def read_items():
return [{"item": "Foo"}, {"item": "Bar"}]
The verify_token dependency will execute before read_items. If it raises an HTTPException, the path operation will not run, and the client will receive the error.
Manage Dependency Caching
By default, if a dependency is used multiple times in the same request (for example, if multiple sub-dependencies depend on the same database session), FastAPI will cache the result and provide the same value to every consumer.
This behavior is controlled by the use_cache parameter in the Depends class:
class Depends:
dependency: Callable[..., Any] | None = None
use_cache: bool = True
If you need a dependency to be re-executed every time it is called within a single request, set use_cache=False:
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters, use_cache=False)]):
return commons
Override Dependencies for Testing
When writing tests, you often want to replace a real dependency (like a database connection) with a mock or a test-specific version. FastAPI provides the dependency_overrides attribute on the FastAPI app instance for this purpose.
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
async def common_parameters():
return {"q": "original"}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
def override_common_parameters():
return {"q": "overridden"}
def test_dependency_override():
# Set the override
app.dependency_overrides[common_parameters] = override_common_parameters
client = TestClient(app)
response = client.get("/items/")
# Clean up the override after the test
app.dependency_overrides = {}
assert response.json() == {"q": "overridden"}
The app.dependency_overrides dictionary maps the original dependency callable to the replacement callable. This is a powerful tool for isolating components during integration testing.