Skip to content

Адаптеры фреймворков

Адаптеры InferDI связывают типизированный контейнер с жизненным циклом фреймворка. HTTP-адаптеры создают отдельный скоуп на запрос и предоставляют его через объект запроса или контекста. React-адаптер предоставляет типизированный контекст и может управлять дочерним скоупом на клиенте.

Адаптеры отвечают за создание, доступность и освобождение скоупов. Благодаря этому @inferdi/inferdi остаётся без зависимостей и фреймворковой логики. В ядро не добавляются декораторы, сканирование контроллеров и маршрутов или внедрение зависимостей в параметры обработчиков. Интеграция использует жизненный цикл фреймворка.

Пакеты

ПакетФреймворкГде хранится скоупРежим без скоупа запроса
@inferdi/fastifyFastify v5request.diда
@inferdi/honoHono v4c.var.diнет
@inferdi/koaKoa v3ctx.state.diнет
@inferdi/expressExpress 5req.diнет
@inferdi/elysiaElysia v1context.diда
@inferdi/reactReact 19Контекст Reactвнешний Provider

React использует жизненный цикл компонента. Внешний Provider никогда не освобождает переданный контейнер. Управляемый ScopeProvider создаёт дочерний скоуп после фиксации изменений React (commit) и всегда освобождает его. Подробнее на странице React-адаптера.

Общий контракт жизненного цикла

В режиме со скоупами каждый HTTP-адаптер выполняет следующие шаги для каждого запроса:

  1. Создать: в начале запроса адаптер создаёт скоуп через createScope (по умолчанию root.createScope()).
  2. Предоставить доступ: сохраняет скоуп в объекте запроса или контекста фреймворка. Hono, Koa, Express и Elysia делают это до настройки. Fastify заполняет request.di после успешной настройки, а при её ошибке временно предоставляет скоуп на время очистки. Хуки очистки видят скоуп в публичном поле, но обработчики ошибок не получают частично подготовленный скоуп.
  3. Настроить: setupScope выполняет дополнительную инициализацию до запуска обработчиков. Настройка может быть асинхронной.
  4. Обработать запрос: обработчики маршрутов и ошибок получают сервисы из скоупа.
  5. Освободить ресурсы: в подходящий момент жизненного цикла адаптер вызывает disposeScope (по умолчанию scope.dispose()), если владение не передано приложению.

Общие опции

ОпцияПо умолчаниюНазначение
containerобязательнаКорневой контейнер, доступный приложению. Адаптеры его не очищают, кроме Fastify при явно включённом disposeRootOnClose.
createScoperoot.createScope()Создаёт скоуп запроса. Объявленные данные запроса передавайте здесь. Может быть асинхронным.
setupScopeнетВыполняет дополнительную инициализацию до обработчиков. Может быть асинхронным.
disposeScopescope.dispose()Позволяет задать синхронное или асинхронное освобождение ресурсов.
autoDisposetruefalse или предикат, вернувший false, передаёт освобождение ресурсов вашему коду.
onDisposeErrorстандартный обработчик адаптераПринимает ошибки очистки скоупа запроса: Fastify request.log.error, Koa ctx.app.emit('error'), остальные console.error.
skipInferdiDispose(...)-Передаёт приложению ответственность за скоуп одного запроса, например для потокового ответа или фоновой задачи.

Правила ошибок и владения

  • При ошибке настройки передаётся только исходная ошибка. Если setupScope выбрасывает исключение, адаптер пытается освободить частично подготовленный скоуп и передаёт дальше исходное исключение. Ошибка этой очистки поступает в onDisposeError или стандартный обработчик и не добавляется к исходной.
  • Ошибка запроса не отменяет очистку. Маркер skipInferdiDispose пропускает очистку только при успешном ответе. При ошибке скоуп освобождается независимо от маркера, если это допускает autoDispose. Исключение: middleware Express не видит обработанную ошибку маршрута, поэтому при отключённой автоочистке скоуп остаётся во владении приложения.
  • autoDispose: false и skipInferdiDispose передают владение приложению. Ваш код должен сам освободить скоуп в подходящий момент жизненного цикла.
  • Ошибки очистки после отправки ответа поступают в обработчик ошибок. Они не передаются клиенту и не меняют уже отправленный ответ.

Важные различия

АдаптерРазница
FastifyОсвобождает скоуп в onResponse; очистка при обрыве соединения идёт через onRequestAbort; освобождение корневого контейнера включается через disposeRootOnClose.
HonoОсвобождает скоуп после await next(); функции потоковой передачи могут вернуть ответ до завершения потока, поэтому часто нужен skipInferdiDispose.
KoaЖдёт события объекта ответа Node.js finish или close, поэтому обычные тела потоковых ответов не требуют отключения автоочистки.
ExpressНе может увидеть перехваченную ошибку маршрута из middleware с обратными вызовами; упавший запрос с пропущенной автоочисткой остаётся во владении приложения.
ElysiaОчистка привязана к onAfterResponse; если этот хук не вызывается, адаптер не может освободить ресурсы внутри скоупа.