Dependency Injection

Loading concept...

FastAPI Dependency Injection: Your Magic Helper System 🪄

The Big Idea in 30 Seconds

Imagine you’re building a LEGO castle. Instead of searching for the right pieces every time, what if a helper automatically brought you exactly what you need?

That’s Dependency Injection! Your code asks for help, and FastAPI delivers it automatically.


🎭 Our Story: The Restaurant Kitchen

Picture a busy restaurant kitchen. The head chef (your endpoint) needs ingredients, tools, and helpers to cook meals.

Without Dependency Injection:

Chef runs around grabbing salt, finding knives, checking if the fridge is working… exhausting!

With Dependency Injection:

Chef just says “I need salt” and poof — it appears. Magic helpers handle everything!


1. Dependency Injection Basics

What Is It?

Dependency Injection means: “Don’t create things yourself. Ask for them, and they’ll be given to you.”

Think of it like ordering food. You don’t go to the kitchen. You tell the waiter what you want, and they bring it to you.

Why Does This Matter?

Without DI With DI
Your code creates everything Helpers provide what you need
Hard to test Easy to test
Messy spaghetti code Clean, organized code

Simple Mental Model

graph TD A[Your Endpoint] -->|Asks for| B[Dependency] C[FastAPI] -->|Provides| B B -->|Ready to use!| A

Your endpoint just asks. FastAPI delivers.


2. The Depends Function

Your Magic Word

Depends() is like saying “please” to FastAPI. It tells FastAPI: “I need this thing. Please get it for me.”

Your First Dependency

from fastapi import Depends, FastAPI

app = FastAPI()

# This is the helper function
def get_greeting():
    return "Hello!"

# Use Depends to ask for it
@app.get("/")
def read_root(
    greeting: str = Depends(get_greeting)
):
    return {"message": greeting}

What happens:

  1. Someone visits /
  2. FastAPI sees Depends(get_greeting)
  3. FastAPI calls get_greeting() for you
  4. Your function receives "Hello!"

Real-World Example: Getting User Info

def get_current_user():
    # Check login, read token, etc.
    return {"name": "Alice", "role": "admin"}

@app.get("/profile")
def profile(
    user: dict = Depends(get_current_user)
):
    return f"Welcome, {user['name']}!"

You never call get_current_user() yourself. FastAPI does it!

Dependencies with Parameters

def get_items(skip: int = 0, limit: int = 10):
    return {"skip": skip, "limit": limit}

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

Visit /items?skip=5&limit=20 and FastAPI:

  1. Reads skip and limit from the URL
  2. Passes them to get_items
  3. Gives you the result

3. Class-based Dependencies

When Functions Aren’t Enough

Sometimes you need more than a simple function. You need an object with state or configuration.

The Class as a Dependency

class Paginator:
    def __init__(
        self,
        skip: int = 0,
        limit: int = 10
    ):
        self.skip = skip
        self.limit = limit

@app.get("/books")
def get_books(
    page: Paginator = Depends(Paginator)
):
    return {
        "skip": page.skip,
        "limit": page.limit
    }

How It Works

graph TD A[Request: /books?skip=5] --> B[FastAPI] B -->|Creates| C[Paginator object] C -->|skip=5, limit=10| D[Your Endpoint]

FastAPI creates the Paginator object and fills in the values from the request!

Why Use Classes?

  1. Reusable — Use the same paginator everywhere
  2. Type hints — Your IDE knows what page.skip is
  3. Validation — Add checks inside __init__
class Paginator:
    def __init__(
        self,
        skip: int = 0,
        limit: int = 100
    ):
        if limit > 100:
            limit = 100  # Safety limit!
        self.skip = skip
        self.limit = limit

4. Sub-dependencies

Dependencies That Need Other Dependencies

What if your helper needs helpers? Like a chef who needs a sous-chef, who needs a prep cook?

Chain of Dependencies

def get_database():
    return {"connected": True}

def get_user_service(
    db: dict = Depends(get_database)
):
    return {"db": db, "service": "users"}

@app.get("/users")
def list_users(
    service: dict = Depends(get_user_service)
):
    return service

What Happens

graph TD A["/users endpoint"] -->|needs| B[get_user_service] B -->|needs| C[get_database] C -->|returns| D[database connection] D -->|used by| B B -->|returns| E[user service] E -->|used by| A

FastAPI automatically resolves the whole chain!

Real-World Example: Auth Chain

def get_token(
    authorization: str = Header(...)
):
    return authorization.split(" ")[1]

def get_current_user(
    token: str = Depends(get_token)
):
    # Decode token, find user
    return {"id": 1, "name": "Alice"}

def get_admin_user(
    user: dict = Depends(get_current_user)
):
    if user.get("role") != "admin":
        raise HTTPException(403)
    return user

@app.get("/admin/dashboard")
def admin_panel(
    admin: dict = Depends(get_admin_user)
):
    return {"welcome": admin["name"]}

Three levels deep — FastAPI handles it all!


5. Dependencies with Yield

Setup AND Cleanup

Sometimes you need to:

  1. Set up something before your endpoint runs
  2. Clean up after your endpoint finishes

Like opening a door, doing work, then closing the door.

The Yield Pattern

def get_db_connection():
    # SETUP: Open connection
    db = DatabaseConnection()
    db.connect()

    yield db  # Give to endpoint

    # CLEANUP: Close connection
    db.close()

How It Works

graph TD A[Request arrives] --> B[SETUP: Open DB] B --> C[yield db] C --> D[Endpoint runs] D --> E[Endpoint returns] E --> F[CLEANUP: Close DB] F --> G[Response sent]

Everything after yield runs AFTER your endpoint finishes!

Complete Example

def get_file_handler():
    # Setup
    file = open("data.txt", "r")
    print("File opened!")

    yield file

    # Cleanup (always runs!)
    file.close()
    print("File closed!")

@app.get("/read")
def read_file(
    f = Depends(get_file_handler)
):
    return {"content": f.read()}

Why Yield Matters

Without Yield With Yield
You forget to close connections Auto-cleanup guaranteed
Memory leaks Resources always freed
Manual try/finally everywhere Clean, simple code

6. Global Dependencies

Apply to EVERYTHING

What if you want the same dependency on every single endpoint?

Like a security guard checking ID at the building entrance — not at every room.

Adding Global Dependencies

from fastapi import Depends, FastAPI

def verify_api_key(
    api_key: str = Header(...)
):
    if api_key != "secret123":
        raise HTTPException(401)
    return api_key

# Apply to ALL routes!
app = FastAPI(
    dependencies=[Depends(verify_api_key)]
)

@app.get("/")
def home():
    return {"msg": "You're authorized!"}

@app.get("/data")
def data():
    return {"secret": "stuff"}

Both endpoints automatically check the API key!

Router-Level Dependencies

You can also apply to a group of routes:

from fastapi import APIRouter

admin_router = APIRouter(
    prefix="/admin",
    dependencies=[Depends(get_admin_user)]
)

@admin_router.get("/stats")
def stats():
    return {"users": 100}

@admin_router.get("/logs")
def logs():
    return {"entries": []}

app.include_router(admin_router)

All /admin/* routes require admin access!

Levels of Dependencies

graph TD A[Global Dependencies] -->|apply to| B[Entire App] C[Router Dependencies] -->|apply to| D[Route Group] E[Endpoint Dependencies] -->|apply to| F[Single Route]

Quick Summary

Concept What It Does When to Use
Depends() Asks for a helper Every dependency
Class Dependencies Creates objects Shared configuration
Sub-dependencies Chain of helpers Complex setups
Yield Dependencies Setup + cleanup Database, files, locks
Global Dependencies Applies everywhere Auth, logging, headers

Your Journey So Far 🎉

You’ve learned that Dependency Injection is like having magic helpers:

  1. You ask (using Depends)
  2. FastAPI provides (creating, chaining, cleaning up)
  3. You focus on your code (not plumbing)

No more hunting for ingredients. No more forgetting to close doors. Just clean, powerful, professional code.

You’re ready to build amazing things! 🚀

Loading story...

No Story Available

This concept doesn't have a story yet.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

Interactive Preview

Interactive - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Interactive Content

This concept doesn't have interactive content yet.

Cheatsheet Preview

Cheatsheet - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Cheatsheet Available

This concept doesn't have a cheatsheet yet.

Quiz Preview

Quiz - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.

No Quiz Available

This concept doesn't have a quiz yet.