NestJS モジュール間サービス注入
JavaScript, Node.js, TypeScriptで別のモジュールからNestJSサービスをインジェクションする
NestJSは、Node.jsのフレームワークで、モジュール化と依存性の注入を強力にサポートしています。この機能を活用して、別のモジュールからサービスをインジェクションし、コードの再利用性とテスト性を向上させることができます。
モジュールの作成とサービスの定義
-
サービスを定義します
// my.service.ts import { Injectable } from '@nestjs/common'; @Injectable() export class MyService { // サービスのロジック }
@Injectable
デコレーターを使用して、サービスをインジェクション可能にします。
-
モジュールを作成します
// module-a.module.ts import { Module } from '@nestjs/common'; import { MyService } from './my.service'; @Module({ providers: [MyService], exports: [MyService], }) export cl ass ModuleA {}
@Module
デコレーターを使用して、モジュールを定義します。providers
プロパティにサービスを登録します。exports
プロパティを使用して、他のモジュールからサービスをインポートできるようにします。
他のモジュールからサービスをインジェクション
- 別のモジュールを作成します
// module-b.module.ts import { Module } from '@nestjs/common'; import { ModuleA } from './module-a.module'; import { MyService } from './module-a.module'; // またはインポートパス @Module({ imports: [ModuleA], providers: [ { provide: MyService, useExisting: MyService, // またはuseClass }, ], }) export class ModuleB {}
providers
プロパティを使用して、サービスをインジェクションします。useExisting
トークンを使用して、既にインポートされたサービスを再利用します。
サービスの使用
- コントローラーまたは他のサービスからサービスを使用します
// my-controller.ts import { Controller, Get } from '@nestjs/common'; import { MyService } from './my.service'; @Controller('my') export class MyController { constructor(p rivate readonly myService: MyService) {} @Get() async getSomething() { const result = await this.myService.doSomething(); return result; } }
- コンストラクターでサービスを注入し、メソッド内で使用します。
ポイント
useClass
トークンを使用して、別のクラスのインスタンスを注入できます。- 依存性の注入は、サービスのインスタンスを自動的に提供し、テスト性を向上させます。
- サービスは、特定の機能を提供するクラスです。
- モジュールは、アプリケーションの機能を分割し、再利用性を向上させます。
NestJS モジュール間サービス注入のコード例解説
// module-a.module.ts
import { Module } from '@nestjs/common';
import { MyService } from './my.service';
@Module({
providers: [MyService],
exports: [MyService],
})
export cl ass ModuleA {}
- exports プロパティ
他のモジュールからインポートできるようにするサービスを指定します。 - providers プロパティ
このモジュール内で提供するサービスを登録します。
// my.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class MyService {
// サービスのロジック
}
// module-b.module.ts
import { Module } from '@nestjs/common';
import { ModuleA } from './module-a.module';
import { MyService } from './module-a.module'; // またはインポートパス
@Module({
imports: [ModuleA],
providers: [
{
provide: MyService,
useExisting: MyService, // またはuseClass
},
],
})
export class ModuleB {}
- providers プロパティ
useExisting
を使用して、すでにインポートしたMyService
を再利用します。useClass
を使用して、別のクラスのインスタンスを注入することも可能です。 - imports プロパティ
他のモジュールをインポートし、そのモジュールで提供されるサービスを利用可能にします。
// my-controller.ts
import { Controller, Get } from '@nestjs/common';
import { MyService } from './my.service';
@Controller('my')
export class MyController {
constructor(p rivate readonly myService: MyService) {}
@Get()
async getSomething() {
const result = await this.myService.doSomething();
return result;
}
}
- コンストラクター
MyService
を注入し、this.myService
として使用します。
コード解説
- useClass
別のクラスのインスタンスを注入する場合に使用します。 - useExisting
既にインポートしたサービスを再利用する場合に使用します。
上記のコード例では、ModuleA
で定義された MyService
を ModuleB
からインジェクションし、MyController
で利用しています。これにより、モジュール間の依存関係を明確にし、コードの再利用性を高めることができます。
useExisting
とuseClass
の使い分けを理解することで、より柔軟な依存関係の注入が可能になります。- 依存性の注入は、NestJS のコア機能の一つであり、テストしやすいコードを書くために不可欠です。
- モジュールは、アプリケーションの構造を整理し、機能を分割する上で非常に重要です。
- より複雑なアプリケーションでは、カスタムプロバイダーを作成して、依存関係の注入をカスタマイズすることも可能です。
@Inject() デコレーターによる直接注入
- 柔軟性
任意のトークンを指定してサービスを取得できます。 - シンプルで直感的
サービスを直接コンストラクターに注入します。 - 最も一般的な方法
constructor(@Inject(MyService) private readonly myService: MyService) {}
クラスプロバイダーによる注入
- 複雑なシナリオ
依存関係の注入をより細かく制御したい場合に有効です。 - 柔軟性
サービスの生成ロジックをカスタマイズできます。 - カスタムロジック
providers: [ { provide: MyService, useFactory: (httpService: HttpService) => { return new MyService(httpService); }, inject: [HttpService], }, ],
AsyncProvider による非同期な注入
- 非同期設定
設定ファイルの読み込みなど、非同期な処理が必要な場合に利用します。 - 非同期処理
providers: [ { provide: MyService, useFactory: async (configService: ConfigService) => { const options = configService.get('myServiceOptions'); return new MyService(options); }, inject: [ConfigService], }, ],
SharedModule による共有
- 共通サービス
// SharedModule @Module({ providers: [MyService], exports: [MyService], }) export class SharedModule {}
DynamicModule による動的なモジュール
- 実行時にモジュールを生成
環境変数や設定ファイルに基づいてモジュールを動的に生成できます。
選択のポイント
- 動的生成
DynamicModule は、実行時にモジュールを生成する必要がある場合に利用します。 - 共有
SharedModule は、共通のサービスを共有する際に便利です。 - 柔軟性
クラスプロバイダーやAsyncProviderは、より柔軟な注入を可能にします。 - シンプルさ
@Inject()
は最もシンプルで直感的な方法です。
NestJSでは、モジュール間でサービスを注入する方法は多岐にわたります。各方法にはメリットとデメリットがあり、プロジェクトの要件に合わせて適切な方法を選択することが重要です。
どの方法を選ぶべきか?
- 実行時にモジュールを生成したい場合
DynamicModule - 非同期処理が必要な場合
AsyncProvider - カスタムロジックが必要な場合
クラスプロバイダー - シンプルで共通のサービス
@Inject()
または SharedModule
これらの方法を組み合わせることで、より複雑な依存関係の管理も可能になります。
@Global()
デコレーターを使用して、グローバルなモジュールを作成し、すべてのモジュールからアクセスできるようにすることができます。@Optional()
デコレーターを使用して、サービスが注入できない場合のデフォルト値を設定できます。
javascript node.js typescript