Fastapi Path Operation Dependencies
FastAPI provides a powerful and concise dependency injection system.
Dependency injection is a design pattern that allows you to extract common logic (such as database connections, authentication, parameter validation, etc.) into reusable components, which can then be used in routes as needed.
!(#)
* * *
## What is Dependency Injection
Simply put, a **dependency** is a function that can use the same parameters as path operation functions (query parameters, path parameters, request body, etc.). FastAPI will automatically call the dependency function before executing the route function and pass its return value to the route function.
## Example
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
# 1. Define dependency function
def common_parameters(q: str | None=None, skip: int=0, limit: int=100):
return{"q": q,"skip": skip,"limit": limit}
# 2. Use dependency in route
@app.get("/items/")
async def read_items(commons: dict= Depends(common_parameters)):
# commons receives the return value of the dependency function
return commons
@app.get("/users/")
async def read_users(commons: dict= Depends(common_parameters)):
# Multiple routes can reuse the same dependency
return commons
Code Explanation:
| Part | Description |
| --- | --- |
| `common_parameters` | Dependency function for handling common query parameters |
| `Depends(common_parameters)` | Declares that the value of parameter `commons` comes from the dependency function |
| `commons: dict` | Receives the dictionary returned by the dependency function |
> Both dependency functions and path operation functions use the same parameter declaration method. FastAPI will automatically parse the parameters of the dependency function. This means that dependency functions can also use query parameters, path parameters, request body, etc.
* * *
## Execution Flow of Dependencies
When a request arrives, the processing order in FastAPI:
1. Identify the route function and its dependencies
2. Execute dependency functions (in dependency order)
3. Pass the return value of the dependency function to the route function
4. Execute the route function
* * *
## Using Classes as Dependencies
Besides functions, you can also use classes as dependencies:
## Example
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
# Declare dependency using class
class CommonQueryParams:
def __init__ (self, q: str | None=None, skip: int=0, limit: int=100):
self.q= q
self.skip= skip
self.limit= limit
# Use class as dependency
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
return{"q": commons.q,"skip": commons.skip,"limit": commons.limit}
When `Depends()` is not passed any arguments, FastAPI will automatically use the type annotation of the parameter (`CommonQueryParams`) as the dependency.
* * *
## Sub-dependencies
Dependencies can have their own dependencies, forming a chain of dependencies:
## Example
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
# Dependency function
def query_extractor(q: str | None=None):
return q
# Sub-dependency: depends on query_extractor
def query_checker(q: str= Depends(query_extractor)):
if q =="admin":
# Sub-dependency can perform validation
return q + " (checked)"
return q
# Route uses sub-dependency
@app.get("/items/")
async def read_items(q: str= Depends(query_checker)):
return{"q": q}
Execution flow: `query_extractor` -> `query_checker` -> route function
* * *
## Using Dependencies in Decorators
Sometimes you only need the side effects of a dependency (such as permission verification) without its return value. You can declare it in the `dependencies` parameter of the decorator:
## Example
from fastapi import Depends, FastAPI, Header, HTTPException
app = FastAPI()
# Dependency: validate API Key
async def verify_api_key(x_api_key: str= Header()):
if x_api_key !="secret-key":
raise HTTPException(status_code=400, detail="X-API-Key invalid")
# Use dependency in decorator, no return value needed
@app.get("/items/", dependencies=[Depends(verify_api_key)])
async def read_items():
return[{"item": "Foo"}]
# Apply dependency to an entire route group
@app.get("/users/", dependencies=[Depends(verify_api_key)])
async def read_users():
return[{"user": "Bar"}]
* * *
## Global Dependencies
You can declare global dependencies on the `FastAPI` instance to apply them to all routes:
## Example
from fastapi import Depends, FastAPI, Header, HTTPException
async def verify_token(x_token: str= Header()):
if x_token !="fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
# Global dependency: all routes require token verification
app = FastAPI(dependencies=[Depends(verify_token)])
@app.get("/items/")
async def read_items():
return[{"item": "Foo"}]
@app.get("/users/")
async def read_users():
return[{"user": "Bar"}]
* * *
## Dependencies Using yield
When a dependency needs to perform cleanup operations (such as closing database connections), use `yield`:
## Example
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
# Dependency using yield: create connection before request, close after request
def get_db():
db ="database_connection"# Simulate creating database connection
try:
yield db # Provide database connection during request processing
finally:
print("Closing database connection")# Clean up resources after request
@app.get("/items/")
async def read_items(db: str= Depends(get_db)):
return{"db": db}
Execution flow:
1. When the request arrives, execute the code before `yield`, create database connection
2. `yield` passes the connection to the route function
3. After the route function completes execution, execute the cleanup code in the `finally` block
> `yield` dependencies are ideal for managing resources that need cleanup, such as database connections, file handles, etc. The cleanup code will execute regardless of whether the route function throws an exception.
* * *
## Summary
* Dependency injection extracts common logic into reusable functions or classes
* Use `Depends()` in route function parameters to declare dependencies
* Dependencies can be nested, forming dependency chains
* The `dependencies` parameter in decorators is used for dependencies that don't require return values
* Dependencies using `yield` support resource cleanup
* Global dependencies apply to all routes
YouTip