Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,66 @@
[![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)

Integration of [Modern-DI](https://github.com/modern-python/modern-di) to FastAPI
[Modern-DI](https://github.com/modern-python/modern-di) integration for [FastAPI](https://fastapi.tiangolo.com).

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` registers the container and builds a per-request child container automatically; `FromDI` resolves a provider (or type) into a route parameter.

```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], validate=True)
setup_di(app, container)


@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.

## API

| Symbol | Description |
|---|---|
| `setup_di(app, container)` | Stores the container on `app.state` and appends a lifespan that closes it on shutdown (merges with any existing `lifespan=`) |
| `FromDI(provider, *, use_cache=True)` | FastAPI `Depends` that resolves a provider (or type) from the per-request child container |
| `fetch_di_container(app)` | Returns the app-scoped container from `app.state` |
| `build_di_container(connection)` | FastAPI `Depends` callable that yields the per-request child container — `REQUEST` scope for an HTTP request, `SESSION` scope for a WebSocket |
| `fastapi_request_provider` | `ContextProvider` for the current `fastapi.Request` |
| `fastapi_websocket_provider` | `ContextProvider` for the current `fastapi.WebSocket` |

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

## 📝 [License](LICENSE)
Expand Down