Внедрение зависимостей¶
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования, который помогает писать слабосвязанный, легко тестируемый и расширяемый код. Вместо того чтобы обработчики сами создавали нужные им объекты (зависимости), они получают их извне.
Argenta использует библиотеку dishka для реализации DI, что позволяет декларативно объявлять зависимости прямо в сигнатурах ваших обработчиков.
Подробнее о DI, IoC и API для создания провайдеров можно прочитать в официальной документации dishka.
Основная идея¶
Представьте, что вашему обработчику для работы нужен доступ к базе данных. Вместо импорта и инициализации соединения внутри функции, вы просто объявляете его как аргумент с аннотацией типа:
Примечание
argenta.di.FromDishka является алиасом для dishka.FromDishka, и они полностью взаимозаменяемы.
Пример использования:
1from sqlite3 import Connection
2from argenta import Response, Router
3from argenta.di import FromDishka
4
5router = Router()
6
7@router.command("connect")
8def connect_handler(response: Response, connection: FromDishka[Connection]):
9 connection.execute("...")
Argenta с помощью dishka разрешит зависимость по типу Connection и внедрит её. Но прежде чем использовать зависимость, её необходимо объявить в провайдере:
Пример использования:
1import sqlite3
2from sqlite3 import Connection
3from typing import Iterable
4
5from dishka import Provider, Scope, provide
6
7
8class ConnectionProvider(Provider):
9 @provide(scope=Scope.REQUEST)
10 def new_connection(self) -> Iterable[Connection]:
11 conn = sqlite3.connect(":memory:")
12 yield conn
13 conn.close()
После создания провайдера его необходимо зарегистрировать в оркестраторе.
Примечание
Провайдеры регистрируются в Orchestrator, а не в App, так как оркестратор отвечает за настройку DI-контейнера на уровне всего приложения. Вы можете передать список из нескольких провайдеров через параметр custom_providers.
Пример использования:
1from argenta import Orchestrator
2
3orchestrator = Orchestrator(custom_providers=[ConnectionProvider()])
Как это работает?¶
В основе DI в Argenta лежат провайдеры и контейнер.
Провайдер (Provider) — это «рецепт», который объясняет, как создавать и настраивать ту или иную зависимость (например, подключение к БД, API-клиент или любой другой сервис).
Контейнер (IoC Container) — это «фабрика», которая хранит все рецепты (провайдеры) и по запросу создаёт и выдаёт готовые зависимости.
Встроенные провайдеры¶
Argenta поставляется со встроенным провайдером, который даёт доступ к важным системным зависимостям без дополнительной настройки. Например, вы можете получить объект ArgSpace, который содержит аргументы командной строки, переданные при запуске приложения.
Пример использования:
1from argenta import Response, Router
2from argenta.di import FromDishka
3from argenta.orchestrator.argparser import ArgSpace
4
5router = Router()
6
7@router.command("info")
8def connect_handler(response: Response, argspace: FromDishka[ArgSpace]):
9 print(argspace.get_by_name("type"))
Обмен данными между обработчиками¶
Помимо DI, обработчики могут обмениваться данными в рамках сессии через объект контекста. В Argenta эту роль выполняет объект DataBridge.
Каждый обработчик может записывать в него данные, а также читать, обновлять и удалять их.
См. также
Подробнее об этом можно прочитать в разделе DataBridge.