Metadata-Version: 2.4
Name: modern-di-fastapi
Version: 4.0.2
Summary: modern-di integration for FastAPI
Keywords: dependency-injection,di,ioc-container,modern-di,fastapi,python,asyncio
Author: Artur Shiriev
Author-email: Artur Shiriev <me@shiriev.ru>
License-Expression: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: Libraries
Requires-Dist: fastapi>=0.100,<1
Requires-Dist: modern-di>=4,<5
Requires-Python: >=3.11, <4
Project-URL: Homepage, https://modern-di.modern-python.org
Project-URL: Documentation, https://modern-di.modern-python.org/integrations/fastapi/
Project-URL: Repository, https://github.com/modern-python/modern-di-fastapi
Project-URL: Issues, https://github.com/modern-python/modern-di-fastapi/issues
Project-URL: Changelog, https://github.com/modern-python/modern-di-fastapi/releases
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)"  srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-fastapi/lockup-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-fastapi/lockup-light.svg">
    <img alt="modern-di-fastapi" src="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-fastapi/lockup.png" width="420">
  </picture>
</p>

[![PyPI version](https://img.shields.io/pypi/v/modern-di-fastapi.svg)](https://pypi.org/project/modern-di-fastapi/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/modern-di-fastapi.svg)](https://pypi.org/project/modern-di-fastapi/)
[![Downloads](https://static.pepy.tech/badge/modern-di-fastapi/month)](https://pepy.tech/projects/modern-di-fastapi)
[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/modern-python/modern-di-fastapi/actions/workflows/ci.yml)
[![CI](https://github.com/modern-python/modern-di-fastapi/actions/workflows/ci.yml/badge.svg)](https://github.com/modern-python/modern-di-fastapi/actions/workflows/ci.yml)
[![License](https://img.shields.io/github/license/modern-python/modern-di-fastapi.svg)](https://github.com/modern-python/modern-di-fastapi/blob/main/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/modern-python/modern-di-fastapi)](https://github.com/modern-python/modern-di-fastapi/stargazers)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty)

[modern-di](https://github.com/modern-python/modern-di) integration for [FastAPI](https://fastapi.tiangolo.com).

Full guide: [FastAPI integration docs](https://modern-di.modern-python.org/integrations/fastapi/)

Usage example: [fastapi-sqlalchemy-template](https://github.com/modern-python/fastapi-sqlalchemy-template)

## Installation

```bash
uv add modern-di-fastapi      # or: pip install modern-di-fastapi
```

## Usage

`setup_di` stores the container on the app and opens and closes it with the app lifespan. `FromDI` resolves a provider (or type) into a route parameter. It builds the per-connection child container on demand through `Depends(build_di_container)`, so only routes that use `FromDI` get one.

```python
import dataclasses

import fastapi
from modern_di import Container, Group, Scope, providers
from modern_di_fastapi import FromDI, setup_di


@dataclasses.dataclass(kw_only=True)
class Settings:
    debug: bool = True


@dataclasses.dataclass(kw_only=True)
class UserService:
    settings: Settings  # auto-injected by type


class Dependencies(Group):
    settings = providers.Factory(scope=Scope.APP, creator=Settings)
    user_service = providers.Factory(scope=Scope.REQUEST, creator=UserService)


app = fastapi.FastAPI()
container = Container(groups=[Dependencies])
setup_di(app, container)
container.validate()  # optional fail-fast; must come after setup_di registers its providers


@app.get("/")
async def index(user_service: UserService = FromDI(Dependencies.user_service)) -> dict[str, bool]:
    return {"debug": user_service.settings.debug}
```

The framework `Request` / `WebSocket` are resolvable within DI via the pre-built `fastapi_request_provider` / `fastapi_websocket_provider` context providers.

An app mounted under another with `app.mount` can call `setup_di` with its own container, and its routes resolve from that container. Starlette runs only the outermost app's lifespan, so the outer app's lifespan also opens and closes the root container of every mounted app that called `setup_di`, including apps under `Host` routes, apps mounted with `Mount(..., middleware=[...])`, and apps mounted more than one level deep. It looks for them at startup, so mounts added after `setup_di` are included. Each container is opened once and closed at shutdown, after your lifespan code. The mounted app's own lifespan function still does not run.

## API

| Symbol | Description |
|---|---|
| `setup_di(app, container)` | Stores the container on `app.state` and composes the container's open/close into the app lifespan (nesting inside any existing `lifespan=`) |
| `FromDI(dependency, *, use_cache=True)` | FastAPI `Depends` that resolves a provider (or type) from the per-connection child container. Raises `RuntimeError` naming `setup_di` when a request reaches it without `setup_di` called |
| `fetch_di_container(app)` | Returns the app-scoped container from `app.state`. Raises `RuntimeError` naming `setup_di` when called without `setup_di` called |
| `build_di_container(connection)` | FastAPI `Depends` callable that yields the per-connection child container: `REQUEST` scope for an HTTP request, `SESSION` scope for a WebSocket |
| `fastapi_request_provider` | `ContextProvider` for the current `fastapi.Request` (`REQUEST` scope) |
| `fastapi_websocket_provider` | `ContextProvider` for the current `fastapi.WebSocket` (`SESSION` scope) |

## 📦 [PyPI](https://pypi.org/project/modern-di-fastapi)

## 📝 [License](https://github.com/modern-python/modern-di-fastapi/blob/main/LICENSE)

## Part of `modern-python`

Built on [`modern-di`](https://github.com/modern-python/modern-di), a dependency-injection framework with an IoC container and scopes.

Browse the full list of templates and libraries in
[`modern-python`](https://github.com/modern-python); the org profile has the categorized index.
