Module

モジュール

モジュールはコントローラやサービスなどプロパティの集まりで、@Moduleデコレータが付けられたクラスです。 @Moduleデコレータは、Nestがアプリケーション構造を整理するために使用します。

f:id:adrenaline2017:20191130162643p:plain

各アプリケーションには少なくとも1つのルートモジュールがあります。 ルートモジュールは、ツリーの頂点に位置するモジュールです。アプリケーションが小さい場合 、ルートモジュールがアプリケーション内の唯一のモジュールになりますが、大規模なアプリケーションではいくつかのモジュールがあり、それぞれが密接に関連します。

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})

export class AppModule {}
imports このモジュールで必要とするインポートされたモジュールのリスト
controllers 作成しなければならないコントローラ
providers コントローラ以外のクラス(サービスなど)を記載
exports 他のモジュールで利用できるプロバイダの一部

モジュールは、デフォルトでプロバイダをカプセル化します。 つまりこれはモジュールの一部でなく、インポートされたモジュールからエクスポートされていないプロバイダを注入することは出来ないこと意味します。

フィーチャーモジュール(モジュールのimports)

CatsControllerとCatsServiceは同じアプリケーションに属します。 フィーチャモジュールであるCatsModuleに移動します。

cats/cats.module.ts

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

ヒント モジュールを作成するには$ nest g module catsコマンドを実行します。 cats.module.tsファイルを定義した後、このモジュールに関連するすべてをcatsディレクトリに移動しました。 最後に、このモジュールをルートモジュール(ApplicationModule)にインポートする必要があります。

app.module.ts

import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class ApplicationModule {}

ApplicationModuleのほかにCatsModuleも登録することが不可欠になります。

共有モジュール(モジュールのexports)

モジュールは任意のプロバイダの同じインスタンスをモジュール間で簡単に共有できます。

f:id:adrenaline2017:20191130162835p:plain

すべてのモジュールは共有モジュールです。 作成後はどのモジュールでも再利用できます。 他のいくつかのモジュール間でCatsServiceインスタンスを共有したいと考えてみましょう。 そのためには、以下のようにCatsServiceをexporotsで配置する必要があります。

cats.module.ts JS

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService]
})
export class CatsModule {}

CatsModuleをインポートする各モジュールは、CatsServiceへのアクセス権を持ちます。このモジュールをインポートする全てのモジュールと同じインスタンスを共有します。

モジュールの再エクスポート

モジュールは内部プロバイダをエクスポートできます。 さらに、彼ら自身がインポートしたモジュールをエクスポートすることもできます。

@Module({
  imports: [CommonModule],
  exports: [CommonModule],
})
export class CoreModule {}

依存性注入(DI)

モジュールクラスは、プロバイダを注入することもできます:

cats.module.ts

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {
  //ここでプロバイダを注入
  constructor(private readonly catsService: CatsService) {}
}

ただし、モジュールクラスはプロバイダによってインジェクトできません。

グローバルモジュール

同じモジュールをどこにでもインポートする必要がある場合は、グローバルモジュールにする必要があります。 Angularでは、プロバイダはグローバルスコープに登録されています。なので定義されると、どこでも利用できます。 一方、Nestはモジュールスコープ内のプロバイダをカプセル化されます。 モジュールのプロバイダをインポートせずに他の場所で使用することはできません。 しかし、時には、ヘルパー、データベース接続など、いつでもすぐに利用できる様にしたいこともあります。 そのために、モジュールを@Global()デコレータでグローバルなものにすることができます。

import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Global()
@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService]
})
export class CatsModule {}

@Global()デコレータは、モジュールをグローバルスコープにします。 グローバルモジュールは、ルートモジュールまたはコアモジュールによって1回だけ登録することが望ましいです。

ヒント 単純に全てをグローバルにすることは良いことではありません。 グローバルモジュールは、必要な定型文の量を減らすために利用できます。 インポート配列は、モジュールAPIを透過的にする最も良い方法です。

ダイナミックモジュール

Nestのモジュールシステムには、動的モジュールと呼ばれる機能があります。 これは、努力せずにカスタマイズ可能なモジュールを作成することができます。 DatabaseModuleを見てみましょう:

import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';

@Module({
  providers: [Connection],
})
export class DatabaseModule {
  static forRoot(entities = [], options?): DynamicModule {
    const providers = createDatabaseProviders(options, entities);
    return {
      module: DatabaseModule,
      providers: providers,
      exports: providers,
    };
  }
}

ヒント forRoot()は、動的に同期または非同期のいずれかのモジュールを返します(Promise)。

このモジュールは、デフォルトでConnectionプロバイダを定義しますが、渡されたオプションやエンティティに応じて、リポジトリなどのプロバイダのコレクションを公開します。 実際、動的モジュールは基本モジュールのメタデータを拡張します。 この実質的な機能は、プロバイダを動的に登録する必要がある場合に便利です。 次に、次のようにDatabaseModuleをインポートできます。

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [
    DatabaseModule.forRoot([User]),
  ],
})
export class ApplicationModule {}

動的モジュールをエクスポートするには、関数呼び出し部分を省略することができます。

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [
    DatabaseModule.forRoot([User]),
  ],
  exports: [DatabaseModule]
})
export class ApplicationModule {}