|
1 | | -# modern-di-aiohttp |
| 1 | +<p align="center"> |
| 2 | + <picture> |
| 3 | + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-aiohttp/lockup-dark.svg"> |
| 4 | + <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-aiohttp/lockup-light.svg"> |
| 5 | + <img alt="modern-di-aiohttp" src="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-aiohttp/lockup.png" width="420"> |
| 6 | + </picture> |
| 7 | +</p> |
2 | 8 |
|
3 | | -[modern-di](https://modern-di.modern-python.org) integration for |
4 | | -[aiohttp](https://docs.aiohttp.org). |
| 9 | +[](https://pypi.org/project/modern-di-aiohttp/) |
| 10 | +[](https://pypi.org/project/modern-di-aiohttp/) |
| 11 | +[](https://pepy.tech/projects/modern-di-aiohttp) |
| 12 | +[](https://github.com/modern-python/modern-di-aiohttp/actions/workflows/ci.yml) |
| 13 | +[](https://github.com/modern-python/modern-di-aiohttp/actions/workflows/ci.yml) |
| 14 | +[](https://github.com/modern-python/modern-di-aiohttp/blob/main/LICENSE) |
| 15 | +[](https://github.com/modern-python/modern-di-aiohttp/stargazers) |
| 16 | +[](https://github.com/astral-sh/uv) |
| 17 | +[](https://github.com/astral-sh/ruff) |
| 18 | +[](https://github.com/astral-sh/ty) |
| 19 | + |
| 20 | +[Modern-DI](https://github.com/modern-python/modern-di) integration for [aiohttp](https://docs.aiohttp.org). |
| 21 | + |
| 22 | +## Installation |
5 | 23 |
|
6 | 24 | ```bash |
7 | | -uv add modern-di-aiohttp |
| 25 | +uv add modern-di-aiohttp # or: pip install modern-di-aiohttp |
| 26 | +``` |
| 27 | + |
| 28 | +## Usage |
| 29 | + |
| 30 | +aiohttp has no dependency-injection system of its own, so `modern-di-aiohttp` pairs an `@inject` decorator with inert `FromDI` markers. `setup_di` stores the container on the app, opens it on startup and closes it on cleanup, and installs middleware that builds a per-connection child container automatically; `FromDI` resolves a provider (or type) into a handler parameter. |
| 31 | + |
| 32 | +```python |
| 33 | +import dataclasses |
| 34 | +import typing |
| 35 | + |
| 36 | +from aiohttp import web |
| 37 | +from modern_di import Container, Group, Scope, providers |
| 38 | +from modern_di_aiohttp import FromDI, inject, setup_di |
| 39 | + |
| 40 | + |
| 41 | +@dataclasses.dataclass(kw_only=True) |
| 42 | +class Settings: |
| 43 | + debug: bool = True |
| 44 | + |
| 45 | + |
| 46 | +@dataclasses.dataclass(kw_only=True) |
| 47 | +class UserService: |
| 48 | + settings: Settings # auto-injected by type |
| 49 | + |
| 50 | + |
| 51 | +class Dependencies(Group): |
| 52 | + settings = providers.Factory(scope=Scope.APP, creator=Settings) |
| 53 | + user_service = providers.Factory(scope=Scope.REQUEST, creator=UserService) |
| 54 | + |
| 55 | + |
| 56 | +@inject |
| 57 | +async def index( |
| 58 | + request: web.Request, |
| 59 | + user_service: typing.Annotated[UserService, FromDI(Dependencies.user_service)], |
| 60 | +) -> web.Response: |
| 61 | + return web.json_response({"debug": user_service.settings.debug}) |
| 62 | + |
| 63 | + |
| 64 | +app = web.Application() |
| 65 | +app.router.add_get("/", index) |
| 66 | +setup_di(app, Container(groups=[Dependencies], validate=True)) |
8 | 67 | ``` |
9 | 68 |
|
10 | | -See the [aiohttp integration docs](https://modern-di.modern-python.org/integrations/aiohttp/). |
| 69 | +An HTTP request opens a `Scope.REQUEST` child container; a WebSocket connection opens a `Scope.SESSION` one. The connection `aiohttp.web.Request` is resolvable within DI: HTTP handlers and `REQUEST`-scoped factories inject it by type via `aiohttp_request_provider`, while WebSocket handlers read it via `FromDI(aiohttp_websocket_provider)`. For per-message work inside a WebSocket handler, open a nested `Scope.REQUEST` child of the session container fetched with `fetch_request_container`. |
| 70 | + |
| 71 | +## API |
| 72 | + |
| 73 | +| Symbol | Description | |
| 74 | +|---|---| |
| 75 | +| `setup_di(app, container)` | Stores the container on the app, wires `on_startup`/`on_cleanup` (reopen on startup, close on cleanup), registers the connection providers, and installs the per-connection middleware | |
| 76 | +| `inject(handler)` | Decorator that resolves every `FromDI`-marked parameter from the request's child container and passes them to the handler | |
| 77 | +| `FromDI(dependency)` | Inert `Annotated` marker resolved by `@inject`; accepts a provider or a type | |
| 78 | +| `fetch_di_container(app)` | Returns the app-scoped root container | |
| 79 | +| `fetch_request_container(request)` | Returns the per-connection child container the middleware built for this request | |
| 80 | +| `aiohttp_request_provider` | `ContextProvider` for the current `aiohttp.web.Request` (`REQUEST` scope) | |
| 81 | +| `aiohttp_websocket_provider` | `ContextProvider` for the connection `aiohttp.web.Request` at WebSocket `SESSION` scope | |
| 82 | + |
| 83 | +## 📦 [PyPI](https://pypi.org/project/modern-di-aiohttp) |
| 84 | + |
| 85 | +## 📝 [License](LICENSE) |
| 86 | + |
| 87 | +## Part of `modern-python` |
| 88 | + |
| 89 | +Built on [`modern-di`](https://github.com/modern-python/modern-di), a dependency-injection framework with IoC container and scopes. |
| 90 | + |
| 91 | +Browse the full list of templates and libraries in |
| 92 | +[`modern-python`](https://github.com/modern-python) — see the org profile for the categorized index. |
0 commit comments