> ## Documentation Index
> Fetch the complete documentation index at: https://fastapi2day.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# FastAPI Dependency Injection with Depends() Explained

> Understand Dependency Injection and Inversion of Control, then learn how FastAPI's Depends() injects database sessions, services, and current users.

Dependency Injection (DI) is one of the most important patterns used in production-grade FastAPI applications, yet it's often misunderstood because it comes bundled with related (but different) concepts. Before you start using `Depends()`, it helps to understand what a dependency actually is, why injecting it from outside is better than creating it internally, and how this relates to the Inversion of Control principle. Once those ideas click, `Depends()` becomes the most natural thing in the world.

***

## What is a Dependency?

A **dependency** is any object, resource, or service that a function or class needs in order to do its work. In a FastAPI application, your endpoints often depend on things like:

* A database session
* A repository or service class
* The currently authenticated user
* Configuration settings
* An external API client
* A logger

> **A dependency is simply something your code needs to do its job.**

***

## What is Dependency Injection?

**Dependency Injection (DI)** is a design pattern where a function or object receives its dependencies from an external source rather than creating them internally.

### Without DI — tightly coupled

```python theme={null}
class StudentService:
    def __init__(self):
        self.printer = Printer()   # creates its own dependency

    def generate_report(self):
        self.printer.print("Student Report")
```

### With DI — loosely coupled

```python theme={null}
class StudentService:
    def __init__(self, printer: Printer):
        self.printer = printer     # dependency provided from outside

    def generate_report(self):
        self.printer.print("Student Report")

printer = Printer()
service = StudentService(printer)  # inject it here
```

The service no longer creates its own dependency. This makes the code:

* **Loosely coupled** — swapping `Printer` for a `MockPrinter` in tests requires no changes to `StudentService`
* **Easier to test** — inject a mock or stub at will
* **Easier to reuse** — the same service works with any compatible printer

***

## What is Inversion of Control?

**Inversion of Control (IoC)** is a design principle where the responsibility for creating objects and managing application flow is delegated to a **framework** rather than your own code.

Without IoC, your application code creates everything:

```text theme={null}
Application
    │
    ├── Create Database
    ├── Create Repository
    ├── Create Service
    └── Call Methods
```

With IoC, the framework takes over:

```text theme={null}
FastAPI
    │
    ├── Create Database
    ├── Create Repository
    ├── Resolve Dependencies
    └── Call Your Endpoint
```

| Concept | Type             | Answers                                                                  |
| ------- | ---------------- | ------------------------------------------------------------------------ |
| **IoC** | Design Principle | "Who controls object creation and application flow?" → The framework.    |
| **DI**  | Design Pattern   | "How are dependencies provided?" → From outside, not created internally. |

<Accordion title="Is Dependency Injection the same as Inversion of Control?">
  No. They are related but different concepts.

  * **IoC** is a design *principle* — it describes who is in control of the application's workflow and object lifecycle.
  * **DI** is a design *pattern* — it describes how dependencies are provided to objects.

  DI is one of the most common techniques used to *achieve* IoC, but IoC can exist without DI (using callbacks or events) and DI can exist without IoC (manual injection where your code still controls creation).
</Accordion>

<Accordion title="Is FastAPI already using DI before I use Depends()">
  Yes. Even before you use `Depends()`, FastAPI already injects values into your endpoint functions:

  ```python theme={null}
  @app.get("/students/{student_id}")
  def get_student(student_id: int, active: bool = True):
      return {"student_id": student_id, "active": active}
  ```

  For `GET /students/101?active=false`, FastAPI automatically injects:

  * `student_id = 101` (from the path)
  * `active = False` (from the query string)

  You never write this extraction code yourself. `Depends()` extends this same mechanism to inject higher-level application resources.
</Accordion>

***

## FastAPI's `Depends()`

FastAPI provides a built-in DI system through the `Depends()` function. When a request arrives, FastAPI:

1. Resolves the dependency (calls the provider function)
2. Injects the result into the endpoint
3. Cleans it up after the request completes (if you use `yield`)

```python theme={null}
from fastapi import Depends, FastAPI

app = FastAPI()

def get_db():
    # In a real app: open a database session
    return {"connection": "active"}

@app.get("/students")
def get_students(db=Depends(get_db)):
    # db is automatically created and injected
    return {"db_status": db["connection"]}
```

***

## Common Dependency Patterns

### Database Session Dependency

```python theme={null}
from fastapi import Depends

def get_db():
    db = SessionLocal()  # open session
    try:
        yield db         # inject into endpoint
    finally:
        db.close()       # clean up after request

@app.get("/employees")
def list_employees(db=Depends(get_db)):
    return db.query(Employee).all()
```

The `yield` pattern ensures the session is always closed, even if the endpoint raises an exception.

### Current User Dependency

```python theme={null}
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer

bearer_scheme = HTTPBearer()

def get_current_user(credentials=Depends(bearer_scheme)):
    # Decode JWT and retrieve user
    token = credentials.credentials
    user = verify_and_decode_token(token)
    if not user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
    return user

@app.get("/profile")
def get_profile(current_user=Depends(get_current_user)):
    return {"user": current_user.username}
```

### Reusable Typed Dependencies with `Annotated`

Use `Annotated` to define a reusable dependency alias once and use it everywhere:

```python theme={null}
from typing import Annotated
from fastapi import Depends

# Define once
DbDep = Annotated[Session, Depends(get_db)]
CurrentUserDep = Annotated[User, Depends(get_current_user)]

# Use everywhere
@app.get("/employees")
def list_employees(db: DbDep, current_user: CurrentUserDep):
    return db.query(Employee).all()

@app.post("/employees")
def create_employee(employee: EmployeeCreate, db: DbDep, current_user: CurrentUserDep):
    ...
```

***

## Dependency Resolution Flow

```text theme={null}
HTTP Request
      │
      ▼
FastAPI
      │
      ▼
Resolve Dependencies
      │
      ├── get_db()
      ├── get_repository()
      ├── get_service()
      └── get_current_user()
      │
      ▼
Inject into Endpoint
      │
      ▼
Execute Endpoint
      │
      ▼
Cleanup (yield-based dependencies)
```

FastAPI resolves dependencies in the correct order — if `get_service()` depends on `get_db()`, FastAPI calls `get_db()` first, then passes the result to `get_service()`, then injects the service into your endpoint. You never manage this order manually.

***

## What FastAPI Can Inject

| Resource                   | Dependency Pattern                               |
| -------------------------- | ------------------------------------------------ |
| Database session           | `get_db()` with `yield`                          |
| Repository / Service       | Constructor injection via `Depends`              |
| Current authenticated user | `get_current_user()` with token verification     |
| Configuration / settings   | `get_settings()` returning a `Settings` instance |
| External API client        | `get_http_client()`                              |
| Logger                     | `get_logger()`                                   |

***

## Benefits

Using `Depends()` across your application delivers:

* **Loose coupling** — endpoints don't know how their dependencies are created
* **Testability** — override any dependency with a mock in tests using `app.dependency_overrides`
* **Reusability** — define a dependency once, inject it in dozens of endpoints
* **Automatic lifecycle management** — `yield` dependencies are always cleaned up
* **Composability** — dependencies can themselves depend on other dependencies

<Tip>
  To override a dependency in tests:

  ```python theme={null}
  def mock_get_db():
      yield fake_db_session

  app.dependency_overrides[get_db] = mock_get_db
  ```

  This replaces the real database with a test fixture for the duration of your tests — no changes to your production code required.
</Tip>
