FastAPI Dependency Injection

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, and then use them as needed in routes.


What is dependency injection

Simply put,DependencyIt is essentially 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 the dependency function
def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


# 2. Use dependencies in routes
@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:

PartDescription
common_parametersDependency functions, handling common query parameters
Depends(common_parameters)Declare parameterscommonsThe value comes from the dependency function
commons: dictReceives the dictionary returned by the dependency function

Dependency functions and path operation functions use the same parameter declaration style, and FastAPI will automatically resolve the parameters of the dependency function. This means dependency functions can also use query parameters, path parameters, request body, etc.


Dependency execution flow

When a request arrives, FastAPI's processing order:

  1. Identify route functions and their dependencies
  2. Execute dependency functions (in dependency order)
  3. Pass the return value of the dependency function to the route function.
  4. Execute route function

Class as a dependency

Besides functions, you can also use classes as dependencies:

Example

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# Declaring Dependencies with Classes
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 a class as a dependency
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
    return {"q": commons.q, "skip": commons.skip, "limit": commons.limit}

WhenDepends()When no parameter is passed, FastAPI automatically uses the type annotation of the parameter (CommonQueryParams) as a dependency.


sub-dependency

Dependencies can have their own dependencies, forming a dependency chain:

Example

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# Dependency Functions
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-dependencies can be validated
        return q + " (checked)"
    return q


# Routes use sub-dependencies
@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 the dependency (such as permission checks), not its return value. In the decorator'sdependenciesDeclared in parameters:

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")


# Using dependency in decorator, no return value required
@app.get("/items/", dependencies=[Depends(verify_api_key)])
async def read_items():
    return [{"item": "Foo"}]


# Apply dependency to the entire route group
@app.get("/users/", dependencies=[Depends(verify_api_key)])
async def read_users():
    return [{"user": "Bar"}]

Global dependencies

You canFastAPIDeclare global dependencies on the instance, effective for 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 need to pass token validation
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), useyield:

Example

from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()


# Dependencies that use yield: create a connection before the request, and close it after the request.
def get_db():
    db = "database_connection"  # Simulate creating a database connection
    try:
        yield db  # Provide a database connection during request handling
    finally:
        print("Close database connection")  # Clean up resources after request completes


@app.get("/items/")
async def read_items(db: str = Depends(get_db)):
    return {"db": db}

Execution flow:

  1. When the request arrives, executeyieldThe code before, creating a database connection
  2. yieldPass the connection to the route function
  3. After the route function completes, executefinallyCleanup code in block

yieldDependencies are ideal for managing resources that require cleanup, such as database connections and file handles. 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.
  • UsageDepends()Declare dependencies in route function parameters
  • Dependencies can be nested, forming dependency chains
  • decorator'sdependenciesParameters used for dependencies that don't need return values
  • UsageyieldDependencies support resource cleanup
  • Global dependencies apply to all routes
other extensions