Nest.jsでコントローラ・サービスを作ってみる

Nest.jsを利用してコントローラとサービスを作ってみます。
<font color="Red">現時点(2019/8/26)でNest.jsの記事が少ないので少しでも貢献できればと思い、簡単な内容ですが書くことにしました</font>

## プロジェクト作成

```console:nestjsのcliをダウンロード
$ npm i -g @nestjs/cli
```

```console:nestjsプロジェクト作成
$ nest new (プロジェクト名)
```

## コントローラの作成
Nest.jsではRubyonRailsのようにCLIを利用してコントローラやサービスを作成可能です。
早速作成してみます。

```console:CLIコマンド
$ nest g controller (コントローラ名)
```

```console:実行結果
$ nest g controller cats
CREATE /src/cats/cats.controller.spec.ts (479 bytes)
CREATE /src/cats/cats.controller.ts (97 bytes)
UPDATE /src/app.module.ts (322 bytes)
```

このコマンドにより、src配下にcatsディレクトリが作成され、その中にcontroller.tsファイルとcontroller.spec.tsファイルが作成されます。
controller.spec.tsファイルはテスト用ファイルです。

app.module.tsファイル内の更新は、今回作成したコントローラを読み込むように修正されています。

### コントローラファイルを修正してみる

CLIで作成されたばかりの状態はこのようになっています。

```javascript:cats.controller.ts(修正前)
import { Controller } from '@nestjs/common';

@Controller('cats')
export class CatsController {}
```

`localhost:3000/cats` でこのコントローラが実行されるように書き換えます。

```javascript:cats.controller.ts(修正後)
import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}
```

実行してみます。

```console
$ npm start

$ curl localhost:3000/cats
This action returns all cats
```

returnに設定した内容が返却されました！
こちらでコントローラはOKです。

もちろん GETだけでなく、POST、PUT、PATCH、DELETEなどのメソッドやクエリストリング・リクエストパラメータの取得も可能ですが、今回は一旦省略します。

## サービスの作成

まずNest.jsの概念図をお見せします。

![Components_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406169/3ec9569d-da90-b41b-96d5-167bf3b2d530.png)
> 画像引用元: [https://docs.nestjs.com/providers](https://docs.nestjs.com/providers)

先ほど作成したコントローラでは、多くのMVCフレームワーク同様に、URIの設計やユーザーからのリクエストを受け取るなどの責務を担います。
実際のビジネスロジックについてはサービスレイヤーで行うべきですので、Nest.jsでも同様にサービスを作る仕組みが用意されています。

こちらもCLIで作成可能です。

```console:CLIコマンド
$ nest g service (サービス名)
```

```console:実行結果
$ nest g service cats
CREATE /src/cats/cats.service.spec.ts (446 bytes)
CREATE /src/cats/cats.service.ts (88 bytes)
UPDATE /src/app.module.ts (386 bytes)
```

このコマンドにより、src配下のcatsディレクトリ内に、service.tsファイルとservice.spec.tsファイルが作成されます。

app.module.tsファイル内の更新は、コントローラと同様に今回作成したサービスを読み込むように修正されています。
また、providersとして、今回作成したサービスが登録されます。

```javascript:app.module.ts
@Module({
  imports: [],
  controllers: [AppController, CatsController],
  providers: [AppService, CatsService],
})
export class AppModule {}
```

app.module.tsファイルのprovidersに登録されたサービスは、DI(いわゆる依存性の注入)が可能になります。

### サービスファイルを修正してみる

ではサービスファイルも修正してみます。
CLIで作成されたばかりの状態はこのようになっています。

```javascript:cats.service.ts(修正前)
import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {}
```

```javascript:cats.controller.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;
  }
}
```

### 色々修正する

CatsServiceの中でCatインターフェースを呼び出しているので、こちらも作成します。

```javascript:src/cats/interface/cat.interface.ts
export interface Cat {
    name: string;
    age: number;
    breed: string;
}
```

Catインターフェースの具象クラスも作成します。

```javascript:src/cats/dto/create-cat.dto.ts
import { Cat } from '../interfaces/cat.interface';

export class CreateCatDto implements Cat {
    readonly name: string;
    readonly age: number;
    readonly breed: string;
}
```

CatsコントローラにもCatを作成・取得するAPIを追加します。
また、先ほど作成した`catsService` をコンストラクタでセットしています。(DI)

```javascript: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();
  }
}
```

## API実行

作成したAPIを実行してみます。

```console
$ npm start

$ curl -X POST localhost:3000/cats -H 'Content-Type:application/json' -d "{\"name\":\"タロー\", \"age\": 1, \"breed\":\"ペルシャ\"}"
$ curl -X POST localhost:3000/cats -H 'Content-Type:application/json' -d "{\"name\":\"マル\", \"age\": 2, \"breed\":\"アメショー\"}"
$ curl localhost:3000/cats
[{"name":"タロー","age":1,"breed":"ペルシャ"},{"name":"マル","age":2,"breed":"アメショー"}]
```

このようにAPIが簡単に作成出来ました。
Nest.jsすごくいいですね！

これからも色々と使ってみて記事を作成してみようと思います。

## 参考
[NestJS公式ドキュメント](https://docs.nestjs.com/)