Backend Development 9 min read

Mastering Dependency Injection in FastAPI: From Basics to Advanced Use

This article explains how FastAPI leverages Dependency Injection to improve code reusability, modularity, and testability, covering basic examples, sub‑dependency handling, database session management with SQLAlchemy, and building a full‑featured user management API with authentication.

Code Mala Tang
Code Mala Tang
Code Mala Tang
Mastering Dependency Injection in FastAPI: From Basics to Advanced Use

Dependency Injection (DI) is a programming technique used to enhance code reusability and decouple classes from their dependencies. In the context of FastAPI, DI plays a key role in optimizing application flexibility, testability, and overall architecture.

Implementing Dependency Injection in FastAPI

FastAPI provides the Depends function to declare dependencies. Here are some common use cases.

Basic Dependency Injection

A simple example injects a function that returns a message.

<code>from fastapi import FastAPI, Depends

def get_message():
    return "Hello from Dependency!"

app = FastAPI()

@app.get("/message")
def read_message(message: str = Depends(get_message)):
    return {"message": message}
</code>

In this example:

get_message() is a dependency.

Depends(get_message) injects its return value into the read_message() function.

Dependency Injection Methods in FastAPI

Use the Depends function.

Handle sub‑dependencies.

The Depends Function

In FastAPI, the Depends function manages dependency injection as a generic parameter for other functions, allowing orderly handling of required components across the application.

Syntax:

@app.get("URL") : decorator that registers a function to handle HTTP GET requests for the specified URL.

def main_function(value: str, list=Depends(dependency_function)) :

<code>@app.get("URL")
def main_function(value: str, list=Depends(dependency_function)):
    pass
</code>

The following example manages a fruit list using a dependency.

<code>from fastapi import FastAPI, HTTPException, status, Depends

# Create fruit list
main_fruits_list = ["Apple"]

app = FastAPI()

def call_main_fruits():
    return main_fruits_list

@app.get("/fruits/")
def test_main_fruits(fruit: str, list=Depends(call_main_fruits)):
    list.append(fruit)
    print(list)
    return {"message": f"Added fruit {fruit} in the list!"}
</code>

Handling Sub‑Dependencies in FastAPI

Managing sub‑dependencies involves organizing additional dependent components, which promotes modular and maintainable code.

Syntax:

<code>async def dependency_function(value: int = Depends(sub_dependency_function)):
    pass
</code>
<code>async def sub_dependency_price(price: int):
    if price == 0:
        return 50
    else:
        return price

async def dependency_fruits(fruit: str, price: int = Depends(sub_dependency_price)):
    return {"Fruit": fruit, "Price": price}

@app.get("/fruits")
async def fetch_authors(fruits_list: dict = Depends(dependency_fruits)):
    return fruits_list
</code>

Below is a practical example building a user‑management API with database access.

Database Dependency Injection

We use SQLAlchemy to manage database sessions and inject them where needed.

<code>pip install fastapi uvicorn sqlalchemy psycopg2 pydantic bcrypt pyjwt
</code>
<code>from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base, Session
from fastapi import Depends

DATABASE_URL = "postgresql://user:password@localhost/db_name"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
</code>

get_db() provides a database session as a dependency.

The yield statement ensures the session is closed after use.

Creating User Model and Authentication Service

<code>class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    hashed_password = Column(String)
</code>

Authentication Service (Injectable Dependency)

We create an AuthService class that handles JWT‑based authentication.

<code>import jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta

SECRET_KEY = "supersecret"
ALGORITHM = "HS256"
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

class AuthService:
    def hash_password(self, password: str) -> str:
        return pwd_context.hash(password)

    def verify_password(self, password: str, hashed_password: str) -> bool:
        return pwd_context.verify(password, hashed_password)

    def create_jwt_token(self, user_id: int):
        expiration = datetime.utcnow() + timedelta(hours=1)
        return jwt.encode({"sub": user_id, "exp": expiration}, SECRET_KEY, algorithm=ALGORITHM)

def get_auth_service():
    return AuthService()
</code>

AuthService is a class‑based dependency.

get_auth_service() returns an injectable instance of AuthService .

Injecting Dependencies in API Routes

<code>from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy.orm import Session
from auth import get_auth_service, AuthService
from database import get_db, User

app = FastAPI()

@app.post("/register/")
def register_user(username: str, password: str, db: Session = Depends(get_db), auth_service: AuthService = Depends(get_auth_service)):
    hashed_password = auth_service.hash_password(password)
    user = User(username=username, hashed_password=hashed_password)
    db.add(user)
    db.commit()
    db.refresh(user)
    return {"message": "User registered successfully"}

@app.post("/login/")
def login_user(username: str, password: str, db: Session = Depends(get_db), auth_service: AuthService = Depends(get_auth_service)):
    user = db.query(User).filter(User.username == username).first()
    if not user or not auth_service.verify_password(password, user.hashed_password):
        raise HTTPException(status_code=400, detail="Invalid credentials")
    token = auth_service.create_jwt_token(user.id)
    return {"access_token": token, "token_type": "bearer"}
</code>

Dependency injection in FastAPI is a powerful mechanism that enhances code modularity and maintainability. By efficiently managing and injecting dependencies, FastAPI enables developers to create well‑structured, scalable, and testable web APIs.

Pythonbackend developmentdependency injectionfastapiWeb API
Code Mala Tang
Written by

Code Mala Tang

Read source code together, write articles together, and enjoy spicy hot pot together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.