Modules | NestJS 【翻訳】

## NestJS公式ドキュメント翻訳

[NestJS公式ドキュメント翻訳](https://qiita.com/mana-vv/items/a658051a5183183c3e50)

## 原文

[Modules | NestJS - A progressive Node.js web framework](https://docs.nestjs.com/modules)

## モジュール

モジュールは`@Module()`デコレータが付けられたクラスです。`@Module()`デコレータはNestがアプリケーション構造を整理するために使用するメタデータを提供します。

![sf.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499074/861f3cbf-8d00-43d9-0a50-84c14019c448.png)

各アプリケーションには少なくとも1つのモジュール、**ルート(root)モジュール**があります。ルートモジュールはNestが**アプリケーショングラフ**の構築の始点です。Nestはモジュールとプロバイダの関係と依存関係を解決するために使用する内部データ構造です。非常に小さなアプリケーションでは、理論的にはルートモジュールがありさえすればよいですが、これは一般的なケースではありません。コンポーネントを整理する効果的な方法としてモジュール化を**強く**お勧めします。ほとんどのアプリケーションではアーキテクチャは複数のモジュールを使用し、各モジュールは密接に関連する機能ごとに**カプセル化**します。

`@Module()`デコレータはプロパティがモジュールを記述する単一のオブジェクトを受け取ります

| | |
|-----------|:-------------|
| `providers`|Nestインジェクタによってインスタンス化され、少なくともそのモジュール全体で共有されるプロバイダ|
| `controllers`|インスタンス化する必要があるそのモジュールで定義されたコントローラのセット|
| `imports`|そのモジュールで必要なプロバイダをエクスポートするインポートされたモジュールのリスト|
| `exports`|そのモジュールによって提供され、そのモジュールをインポートする他のモジュールで利用できる`providers`のサブセット|

モジュールはデフォルトでプロバイダを**カプセル化**します。これは、現在のモジュールの直接的な一部ではなく、インポートされたモジュールからエクスポートされていないプロバイダを注入することは不可能であることを意味します。したがって、モジュールからエクスポートされたプロバイダは、モジュールのパブリックインターフェースまたはAPIと見なすことができます。

### 機能モジュール

`CatsController`と`CatsService`は同じアプリケーションドメインに属します。これらは密接に関連しているため、機能モジュールに移動することは理にかなっています。機能モジュールは特定の機能に関連するコードを整理し明確な境界を確立します。これにより、アプリケーションやチームの規模が大きくなっても、複雑性を管理しつつ[SOLID](https://en.wikipedia.org/wiki/SOLID)の原則に従って開発することができます。

これを実証するために`CatsModule`を作成します。

```typescript: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 {}
```

CLIを使用してモジュールを作成するには、単に`$nest g module cats`コマンドを実行します。

上記では、`cats.module.ts`ファイルで`CatsModule`を定義し、このモジュールに関連するすべてのものを`cats`ディレクトリに移動しました。最後に、このモジュールをルートモジュール（`app.module.ts`ファイルで定義されている`AppModule`）にインポートします。

```typescript:app.module.ts
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

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

ディレクトリ構造は次のようになります。

```
src
 ├── cats
 │   ├── dto
 │   │    └── create-cat.dto.ts
 │   ├── interfaces
 │   │    └── cat.interface.ts
 │   ├── cats.service.ts
 │   ├── cats.controller.ts
 │   └── cats.module.ts
 ├── app.module.ts
 └── main.ts
```

### 共有モジュール

Nestではモジュールはデフォルトでシングルトンなので、複数のモジュール間で任意のプロバイダの同じインスタンスを簡単に共有することができます。

![キャプチャf.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499074/abcbe760-643a-1fb9-40cb-255f0772464d.png)

すべてのモジュールは自動的に**共有モジュール**です。作成すると任意のモジュールで再利用できます。`CatsService`のインスタンスを他のいくつかのモジュール間で共有したいとします。これを行うには、最初に`CatsService`プロバイダをモジュールの`exports`配列に追加して、以下のように**エクスポート**する必要があります。

```typescript:cats.module.ts
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`にアクセスでき、同じインスタンスをそれをインポートする他のすべてのモジュールで共有します。

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

上記のように、モジュールは内部プロバイダをエクスポートできます。さらに、インポートしたモジュールを再エクスポートできます。次の例では、`CommonModule`が`CoreModule`にインポートおよびエクスポートされるため、このモジュールをインポートする他のモジュールで使用できます。

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

### 依存性の注入

モジュールクラスはプロバイダを**注入**することもできます（構成上のためなど）。

```typescript: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) {}
}
```

ただし、[循環依存](https://docs.nestjs.com/fundamentals/circular-dependency)となるためモジュールクラス自体をプロバイダとして注入することはできません。

### グローバルモジュール

どこにでも同じモジュールのセットをインポートする場合、冗長になる可能性があります。 Nestとは異なり、[Angular](https://angular.io/)の`providers`はグローバルスコープに登録されます。定義すればどこでも利用できます。しかし、Nestはプロバイダをモジュールスコープ内にカプセル化します。最初にカプセル化したモジュールをインポートしないと、モジュールのプロバイダを他の場所で使用することはできません。

すぐに使用できるプロバイダのセット（ヘルパー、データベース接続など）を提供する場合は、`@Global()`デコレータを使用してモジュールを**グローバル**にします。

```typescript
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()`デコレータはモジュールをグローバルスコープにします。グローバルモジュールは、通常はルートモジュールまたはコアモジュールによって**一度だけ**登録する必要があります。上記の例では、`CatsService`プロバイダはどこにでもあり、サービスを注入したいモジュールは`imports`配列に`CatsModule`をインポートする必要はありません。

すべてをグローバルにすることは設計上よくありません。必要なボイラープレートを減らすために、グローバルモジュールを使用しましょう。`imports`配列はモジュールのAPIを使う側が利用できるようにするための方法です。

### 動的モジュール

Nestモジュールシステムには、**動的モジュール**と呼ばれる強力な機能が含まれています。この機能により、プロバイダを動的に登録および構成するカスタマイズ可能なモジュールを簡単に作成できます。動的モジュールについては[ここ](https://docs.nestjs.com/fundamentals/dynamic-modules)で詳しく説明します。この章では簡単な概要を示します。

`DatabaseModule`の動的モジュール定義の例を次に示します。

```typescript
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を介して）返します。

このモジュールは`@Module()`デコレータメタデータで`Connection`プロバイダを定義しますが、さらに（`forRoot()`メソッドに渡される`entities`と`options`オブジェクトに応じて）リポジトリなどのプロバイダのコレクションを公開します。動的モジュールによって返されるプロパティは`@Module()`デコレータで定義されたベースモジュールメタデータを（オーバーライドするのではなく）**拡張**することに注意してください。これが、静的に宣言された`Connection`プロバイダ**と**動的に生成されたリポジトリプロバイダの両方をモジュールからエクスポートする方法です。

上記のように定義されると、`DatabaseModule`は次の方法でインポートおよび構成されます。

```typescript
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 AppModule {}
```

動的モジュールを順番に再エクスポートする場合、`exports`配列では`forRoot()`メソッド呼び出しを省略できます。

```typescript
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 AppModule {}
```

[動的モジュール](https://docs.nestjs.com/fundamentals/dynamic-modules)の章では、このトピックをより詳細に説明し[実例](https://github.com/nestjs/nest/tree/master/sample/25-dynamic-modules)を紹介します。