【NestJS】Module間でDIを実装する方法


はじめに

前回の記事でModule内のServiceとRepositoryのDIについて触れたので、今回はModule間でのDIについてまとめました。

実装

以下のように複数のModuleで構成されたアプリケーションがあった場合、別のModuleからServiceを呼び出すためにどのような実装をすればよいかを考えます。

プロジェクト作成

プロジェクトおよび今回必要となるModule、Service、Controllerを作成します。

$ nest new di
$ nest g module computer
$ nest g module cpu
$ nest g module disk
$ nest g module power
$ nest g service cpu
$ nest g service disk
$ nest g service power
$ nest g controller computer

Module間でのDI

Module内のServiceとRepository間のDIは、それぞれに@Injectable()デコレータを付加して、ModuleのprovidersにServiceとRepositoryを登録するだけで実装することができました。

一方、別のModule間のService同士でDIを行うには、別の手順を踏む必要があります。
下図を例にすると以下のようになります。

1. 呼び出される側のModule(PowerModule)のexportsにService(PowerService)を登録する

power.module.ts
import { Module } from '@nestjs/common';
import { PowerService } from './power.service';

@Module({
  providers: [PowerService],
  exports: [PowerService],
})
export class PowerModule {}

2. 呼び出す側のModule(CpuModule)のimportsに1のModule(PowerModule)を登録する

cpu.module.ts
import { Module } from '@nestjs/common';
import { PowerModule } from 'src/power/power.module';
import { CpuService } from './cpu.service';

@Module({
  imports: [PowerModule],
  providers: [CpuService],
})
export class CpuModule {}

3. 呼び出す側のService(CpuService)のconstructorで呼び出される側のService(PowerService)を定義する

cpu.service.ts
import { Injectable } from '@nestjs/common';
import { PowerService } from 'src/power/power.service';

@Injectable()
export class CpuService {
  constructor(private powerService: PowerService) {}

  compute(a: number, b: number) {
    console.log('Drawing 10 watts of power from Power Service');
    this.powerService.supplyPower(10);
    return a + b;
  }
}

PowerModuleとCpuModuleのDIコンテナを図にすると以下のようになります。

CpuModuleでPowerModuleをインポートすることで、PowerModuleのDIコンテナに登録されたリスト(ServiceやServiceとdependencyの関係)がCpuModuleのDIコンテナに登録されます。
NestではModule間のDIがこのようにして行われます。

参考資料