FastAPI Dependency Injection


What is dependency injection in FastAPI?

Dependency injection in FastAPI is a design pattern that allows you to declare external dependencies (such as database connections, services, or authentication mechanisms) in your route functions or classes. FastAPI automatically resolves and provides these dependencies when handling requests, ensuring that your code remains clean, modular, and testable.


How does dependency injection work in FastAPI?

In FastAPI, dependency injection works by using the Depends function, which allows you to declare a dependency that FastAPI will inject into your route function. Dependencies can be functions, classes, or other components that are called when a request is made, and the result is passed into the route handler.

Example of using Depends for dependency injection:

from fastapi import FastAPI, Depends

app = FastAPI()

def common_dependency():
    return {"message": "This is a common dependency"}

@app.get("/items/")
def read_items(dep: dict = Depends(common_dependency)):
    return dep

In this example, the common_dependency function is injected into the read_items route using the Depends function. When a request is made to /items/, FastAPI automatically calls the dependency function and passes the result to the route.


How do you declare multiple dependencies in FastAPI routes?

You can declare multiple dependencies in a FastAPI route by using the Depends function for each dependency. FastAPI resolves all dependencies before calling the route function, ensuring that the dependencies are injected in the correct order.

Example of multiple dependencies:

from fastapi import FastAPI, Depends

app = FastAPI()

def dependency_one():
    return "Dependency One"

def dependency_two():
    return "Dependency Two"

@app.get("/items/")
def read_items(dep1: str = Depends(dependency_one), dep2: str = Depends(dependency_two)):
    return {"dep1": dep1, "dep2": dep2}

In this example, both dependency_one and dependency_two are injected into the read_items route, and their results are returned in the response.


How do you manage database sessions with dependency injection in FastAPI?

One common use case for dependency injection in FastAPI is managing database sessions. You can define a function that creates a database session and inject it into your routes using the Depends function. This ensures that each route has access to a database session that is properly closed after each request.

Example of managing database sessions:

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session
from .database import SessionLocal

app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/items/")
def read_items(db: Session = Depends(get_db)):
    return db.query(models.Item).all()

In this example, the get_db function creates a new database session, and the session is automatically closed after the request is completed. The database session is injected into the read_items route using the Depends function.


What are class-based dependencies in FastAPI?

Class-based dependencies in FastAPI allow you to encapsulate dependency logic within a class. When using class-based dependencies, you can define initialization logic in the __init__ method and inject the class instance into your routes using Depends. This is useful for cases like authentication or service classes.

Example of class-based dependencies:

class AuthService:
    def __init__(self, token: str):
        self.token = token

    def authenticate(self):
        if self.token == "valid_token":
            return {"status": "authenticated"}
        else:
            return {"status": "unauthenticated"}

@app.get("/auth/")
def check_auth(auth_service: AuthService = Depends(AuthService)):
    return auth_service.authenticate()

In this example, the AuthService class is injected into the check_auth route, and its authenticate method is used to determine if the token is valid.


How do you handle dependency injection with parameters in FastAPI?

Dependencies in FastAPI can accept parameters, allowing you to pass data into the dependency function. This is useful when the dependency logic needs input from the request, such as headers, query parameters, or path parameters.

Example of dependencies with parameters:

from fastapi import FastAPI, Depends, Header

app = FastAPI()

def get_token(authorization: str = Header(None)):
    if authorization == "Bearer valid_token":
        return {"status": "valid"}
    return {"status": "invalid"}

@app.get("/items/")
def read_items(token_status: dict = Depends(get_token)):
    return token_status

In this example, the get_token dependency checks the Authorization header and returns the status based on whether the token is valid or not. The result is injected into the read_items route.


How do you handle shared dependencies across multiple routes?

FastAPI allows you to reuse dependencies across multiple routes by simply injecting the same dependency function or class in each route. This reduces code duplication and ensures that common logic, such as authentication or validation, is centralized.

Example of shared dependencies:

from fastapi import FastAPI, Depends

app = FastAPI()

def common_dependency():
    return {"message": "Shared dependency"}

@app.get("/items/")
def read_items(dep: dict = Depends(common_dependency)):
    return dep

@app.get("/users/")
def read_users(dep: dict = Depends(common_dependency)):
    return dep

In this example, the common_dependency function is shared between the /items/ and /users/ routes. FastAPI will automatically inject the dependency into both routes when a request is made.


How do you define dependencies at the FastAPI application level?

In FastAPI, you can define global dependencies that apply to all routes in the application by using the dependencies parameter in the FastAPI instance. This ensures that the dependency is executed for every request, regardless of which route is accessed.

Example of global dependencies:

app = FastAPI(dependencies=[Depends(common_dependency)])

@app.get("/items/")
def read_items():
    return {"message": "Items"}

@app.get("/users/")
def read_users():
    return {"message": "Users"}

In this example, the common_dependency function is applied globally to the entire application, meaning it will be executed for every route, including /items/ and /users/.


What are sub-dependencies in FastAPI?

Sub-dependencies in FastAPI are dependencies that themselves depend on other dependencies. You can create chains of dependencies, where one dependency relies on the result of another. FastAPI resolves the dependencies in the correct order, ensuring that each dependency gets the necessary data.

Example of sub-dependencies:

from fastapi import Depends

def get_db():
    return {"db": "Database connection"}

def get_user(db: dict = Depends(get_db)):
    return {"user": "User data", "db": db}

@app.get("/items/")
def read_items(user: dict = Depends(get_user)):
    return user

In this example, the get_user dependency relies on the get_db dependency. FastAPI first resolves get_db, then uses its result when resolving get_user, and finally passes the user data to the read_items route.


How do you handle asynchronous dependencies in FastAPI?

FastAPI fully supports asynchronous dependencies. You can define dependencies using the async def syntax, and FastAPI will handle them asynchronously, ensuring non-blocking execution.

Example of asynchronous dependencies:

from fastapi import FastAPI, Depends

app = FastAPI()

async def async_dependency():
    return {"message": "Async dependency"}

@app.get("/items/")
async def read_items(dep: dict = Depends(async_dependency)):
    return dep

In this example, the async_dependency function is defined as an asynchronous dependency, and it is injected into the read_items route. FastAPI handles the asynchronous execution of the dependency and the route.

Ads