Fastify アダプター
@inferdi/fastify は Fastify v5 のプラグインです。スコープドモードでは、ルートを app.di として公開し、onRequest で 1 つのリクエストスコープを作成し、それを request.di として公開し、onResponse で破棄します。
インストール
bash
pnpm add @inferdi/inferdi @inferdi/fastify fastifyts
import Fastify, { type FastifyRequest } from 'fastify'
import { Container } from '@inferdi/inferdi'
import { inferdiFastify } from '@inferdi/fastify'リクエストスコープ
モジュール拡張(module augmentation)で具体的なコンテナ型を公開します。
ts
type RequestContext = {
requestId: string
ip: string
}
class Users {
constructor(readonly request: RequestContext) {}
profile(id: string) {
return { id, requestId: this.request.requestId }
}
}
const root = new Container()
.declareScopeInputs<{ request: RequestContext }>()
.registerClass('users', Users, ['request'], 'scoped')
const app = Fastify()
type RootContainer = typeof root
const openRequestScope = (request: FastifyRequest) => root.createScope({
request: {
requestId: request.id,
ip: request.ip
}
})
type RequestContainer = ReturnType<typeof openRequestScope>
declare module 'fastify' {
interface FastifyInstance {
di: RootContainer
}
interface FastifyRequest {
di: RequestContainer
}
}
await app.register(inferdiFastify, {
container: root,
createScope: (_root, request) => openRequestScope(request),
disposeRootOnClose: true
})
app.get('/users/:id', async (request) => {
const { id } = request.params as { id: string }
return request.di.get('users').profile(id)
})Fastify の app.register は、インラインフックに対してプラグインのジェネリクスを十分に深く推論できないため、具体的なスコープ型が必要な場合はフックのパラメータに型注釈を付けてください。
オプション
| オプション | デフォルト | 説明 |
|---|---|---|
container | 必須 | app.di として公開されるルートコンテナ。 |
scopePerRequest | true | ルート専用モードにするには false を設定します。 |
createScope | root.createScope() | カスタムのリクエストスコープ作成。非同期でもかまいません。 |
setupScope | なし | スコープ作成後に追加の初期化を行います。 |
disposeScope | scope.dispose() | カスタムの破棄。同期でも非同期でもかまいません。 |
autoDispose | true | false または false を返す述語は、所有権をアプリケーションコードに移譲します。 |
disposeRootOnClose | false | fastify.close() 中にルートを破棄します。 |
onDisposeError | request.log.error | リクエストスコープの破棄失敗のシンク。 |
ルート専用モード
ハンドラーがシングルトンサービスのみを必要とする場合は、ルート専用モードを使用します。
ts
await app.register(inferdiFastify, {
container: root,
scopePerRequest: false,
})
app.get('/health', async function () {
return this.di.get('health').check()
})ルート専用モードは、リクエストデコレーションもリクエストライフサイクルフックもインストールしません。
ライフサイクルに関する注意
request.diは、セットアップが成功した後にのみ公開されます。- セットアップの失敗は、構築途中のスコープを破棄し、元のセットアップエラーのみを表面化します。
- クリーンアップフックは、実行中に
request.diを参照します。 - 失敗したリクエストは
skipInferdiDisposeを無視し、autoDisposeに従いつつ、それでもスコープを破棄します。 - クライアント中断のクリーンアップは、スコープが公開された後に
onRequestAbortで実行されます。 - ルートの破棄エラーは、
disposeRootOnCloseが有効な場合にのみfastify.close()を通じて伝播します。
autoDispose: false または述語が false を返す場合、レスポンス完了や接続中断の処理後も request.di は利用でき、アプリケーション側で保持したスコープを破棄できます。
