Providers | NestJS 【翻訳】

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

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

## 原文

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

## プロバイダ

プロバイダはNestの基本概念です。基本的なNestクラスの多くはサービス、リポジトリ、ファクトリー、ヘルパーなどのプロバイダとして扱われます。プロバイダのアイデアは依存関係を**注入**できることです。これはオブジェクトが互いにさまざまな関係を作成できることを意味し、オブジェクトのインスタンスを「繋げる」機能はNestランタイムシステムに委任できます。プロバイダは単に`@Injectable()`デコレータが付けられたクラスです。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499074/3adc48e3-7158-ee5e-c7a1-958d8e83a117.png)

前の章では簡単な`CatsController`を作成しました。コントローラはHTTPリクエストを処理し、より複雑なタスクを**プロバイダ**に委任する必要があります。プロバイダはクラス宣言の前に`@Injectable()`デコレータが付いたプレーンなJavaScriptクラスです。

Nestを使用するとオブジェクト指向で依存関係を設計および整理できるため、**SOLID**の原則に従うことを強くお勧めします。

### サービス

まずは、簡単な`CatsService`を作成してみましょう。このサービスはデータの保存と取得を担当し、`CatsController`で使用されるように設計されているためプロバイダとして定義するのに適しています。したがって、クラスを`@Injectable()`で装飾します。

```typescript:cats.service.ts
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';

@Injectable()
export class CatsService {
  private readonly cats: Cat[] = [];

  create(cat: Cat) {
    this.cats.push(cat);
  }

  findAll(): Cat[] {
    return this.cats;
  }
}
```

CLIを使用してサービスを作成するには`$nest g service cats`コマンドを実行します。

`CatsService`は1つのプロパティと2つのメソッドを持つ基本的なクラスです。唯一の新しい機能は`@Injectable()`デコレータを使用している点です。`@Injectable()`デコレータは、このクラスがNestのプロバイダであることをNestに伝えるためのメタデータを付与します。ちなみに、この例では次のような`Cat`インターフェースを使用しています。

```typescript
export interface Cat {
  name: string;
  age: number;
  breed: string;
}
```

catsを取得するサービスクラスができたので、`CatsController`で使用しましょう。

```typescript:cats.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}
```

`CatsService`はコンストラクタを通して**注入**されます。`private readonly`構文が使用されていることに注意してください。これによって、`catsService`メンバーを宣言し同じ場所ですぐに初期化することができます。


### 依存性の注入

Nestは一般的に**依存性注入**と呼ばれる強力な設計パターンをもとに構築されています。[Angular](https://angular.io/guide/dependency-injection)の公式ドキュメントにこの概念に関するわかりやすい記事があるので読むことをお勧めします。

NestではTypeScriptのおかげで依存関係は型ごとに解決されるため、非常に簡単に管理することができます。次の例では、Nestは`CatsService`のインスタンスを作成して返すことにより`catsService`を解決します（または一般的なシングルトンの場合、既に他の場所で使用されている場合は既存のインスタンスを返します）。この依存関係が解決され、コントローラのコンストラクタに渡されます（または指定されたプロパティに割り当てられます）。

```typescript
constructor(private readonly catsService: CatsService) {}
```

### スコープ

プロバイダは通常、アプリケーションのライフサイクルと同期した有効期間（「スコープ」）を持っています。アプリケーションがブートストラップされると、すべての依存関係を解決するためにすべてのプロバイダをインスタンス化する必要があります。同様に、アプリケーションが終了するとプロバイダは破棄されます。ただし、プロバイダの有効期間を**リクエストスコープ**にする方法もあります。この手法の詳細については[こちら](https://docs.nestjs.com/fundamentals/injection-scopes)をご覧ください。

### カスタムプロバイダ

Nestにはプロバイダ間の関係を解決する組み込みの制御の反転（「IoC」）コンテナがあります。この機能は前述の依存性注入機能の基礎になっていますが、実際にはこれまで説明してきた機能よりもはるかに強力です。`@Injectable()`デコレータは氷山の一角にすぎず、プロバイダを定義する唯一の方法ではありません。実際プレーンな値、クラス、および非同期または同期ファクトリーを使用できます。[ここ](https://docs.nestjs.com/fundamentals/custom-providers)でさらに例を示します。

### オプションのプロバイダ

場合によっては必ずしも解決する必要のない依存関係の場合あります。たとえば、クラスは**構成オブジェクト**に依存する場合がありますが、何も渡されない場合はデフォルト値を使用する必要があります。このような場合プロバイダがなくてもエラーにならないため、依存関係はオプションになります。

プロバイダがオプションであることを示すには、コンストラクタで`@Optional()`デコレータを使用します。

```typescript
import { Injectable, Optional, Inject } from '@nestjs/common';

@Injectable()
export class HttpService<T> {
  constructor(
    @Optional() @Inject('HTTP_OPTIONS') private readonly httpClient: T
  ) {}
}
```

上記の例ではカスタムプロバイダを使用していることに注意してください。これが`HTTP_OPTIONS`カスタムトークンを含める理由です。前の例では、コンストラクタのクラスを介した依存関係を示すコンストラクタベースの注入を示しました。カスタムプロバイダとその関連トークンの詳細については[こちら](https://docs.nestjs.com/fundamentals/custom-providers)をご覧ください。

### プロパティベースの注入

プロバイダはコンストラクタを介して注入されるため、これまで使用してきた手法はコンストラクタベースの注入と呼ばれます。非常に特殊なケースですが**プロパティベースの注入**が役立つ場合があります。たとえば、トップレベルのクラスが1つまたは複数のプロバイダに依存している場合、コンストラクタからサブクラスの`super()`を呼び出してそれらを渡すことは非常に面倒です。これを回避するためにプロパティレベルで`@Inject()`デコレータを使用できます。

```typescript
import { Injectable, Inject } from '@nestjs/common';

@Injectable()
export class HttpService<T> {
  @Inject('HTTP_OPTIONS')
  private readonly httpClient: T;
}
```

ただし、クラスが別のプロバイダを拡張しない場合はコンストラクタベースのインジェクションを常に使用することをお勧めします。

### プロバイダの登録

プロバイダ（`CatsService`）を定義しそのサービスのコンシューマー（`CatsController`）を取得したので、注入を実行できるようにNestにサービスを登録する必要があります。これを行うには、モジュールファイル（`app.module.ts`）を編集し、`@Module()`デコレータの`providers`配列にサービスを追加します。

```typescript:app.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';

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

これでNestは`CatsController`クラスの依存関係を解決できるようになります。

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

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