Controllerとは

Controllerとは

NestJSにおけるControllerは、送られてくるリクエストを処理してレスポンスをクライアントに返す枠割を担っています。
Controllerの目的は、アプリケーション内の特定のリクエストを受け取ることです。ルーティングは、どのControllerがどのリクエストを受信するのかを制御します。大半の場合、それぞれのControllerは複数のルートを持ち、異なるルートは異なるアクションを実行できます。
基本的なControllerを作成するために、classdecoratorを活用します。
メモ
NestJSでCRUDモデルのControllerを素早く作成する時、以下のコマンドでCLIのCRUDジェネレータを使えます。 nest g resource [name]

ルーティング設定

以下の例では、基本的なControllerを定義するために@Controller()デコレータを使用します。@Controller()デコレータでパスを指定すると、関連するルートを簡単にグループ化できます。そのため、くり返し使用するコードを最小限に抑えられます。
cats.controller.ts
import { Controller, Get } from '@nestjs/common'
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats'
}
}
メモ
NestJSでControllerを生成する際、以下のコマンドを実行します。 nest g controller cats
findAll()メソッドの前にある@Get()は、HTTPリクエストの特定のエンドポイントに対するハンドラを作成するようにNestJSに命令するデコレータです。エンドポイントは、HTTPリクエストメソッドとルートパスに対応します。
上記の例では、このエンドポイントにGETリクエストが送られると、NestJSはユーザ定義のfindAll()関数にリクエストを転送します。ここで選択されているメソッド名は完全に任意であることには十分留意してください。ルートをバインドするメソッドを宣言する必要はありますが、NestJSは選択したメソッド名に何の意味をもたせません。

デフォルト設定

こちらではリクエストハンドラがJavaScriptのオブジェクトや配列を帰す場合、自動的にJSONにシリアライズされます。ところが、JavaScriptのプリミティブ型(文字列や数値、真偽値のこと)を返す場合、NestJSはシリアライズをせずに値だけを送信します。このため、NestJSのレスポンス処理は簡単になります。

ライブラリ固有(Expressより)

ライブラリ固有のレスポンスオブジェクト使用します。これは、メソッドの中に@Res()デコレータを使って書き入れます。(例えば、findAll(@Res() response)のような感じで)この方法では、そのオブジェクトが公開するネイティブなレスポンス処理メソッドを使うことができます。例えば、Expressではresponse.status(200).send()のようなコードでレスポンスを作成できます。
注意 NestJSは、ハンドラが@Res()あるいは@Next()のどちらを使用しているのかを検出し、ライブラリ固有のオプションを選択したことを示します。両方のアプローチを同時に使用した場合、標準のアプローチはこの単一のルートに対して自動的に無効になり、期待どおりに動作しなくなります。このとき、@Res({ passthrough: true })デコレータでpassthroughオプションをtrueに設定しなければなりません。

リクエストオブジェクトについて

NestJSのハンドラはクライアントのリクエストに詳細にアクセスする必要があります。NestJSでは、基盤となるプラットフォームのリクエストオブジェクトにアクセスする機能を提供します。ハンドラの中身に@Req()デコレータを追加して、リクエストオブジェクトを注入するようにNestに指示することで、リクエストオブジェクトにアクセスできます。
import { Controller, Get, Req } from '@nestjs/common'
import { Request } from 'express'
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request: Request): string {
return 'This action returns all cats'
}
}
メモ
expressライブラリの型付けを利用するために、@types/expressをインストールしてください。
リクエストオブジェクトはHTTPリクエストを意味し、以下の要素を持ちます。
  • リクエストクエリの文字列
  • パラメータ
  • HTTPヘッダー
  • HTTPボディー
大半の場合、これらのプロパティを手動で取得する必要はありません。代用として、@Body()@Query()のような専用のデコレータを使います。
HTTPプラットフォーム間の型付けのの互換性のために、NestJSでは@Res()@Response()デコレータを提供します。@Res()は単に@Response()の型エイリアスです。両方とも、基盤となるネイティブプラットフォームのレスポンスオブジェクトのinterfaceを直接公開します。これらを使うには、基本となるライブラリの型付け(例:@types/express)もインポートして、その利点を最大限に活用する必要があります。メソッド内で@Res()@Response()をインジェクトすると、そのハンドラに対してNestをライブラリ固有のモードにして、レスポンス管理の責任を持つことになることには十分に留意してください。そのとき、レスポンスの呼び出しを行わなければ、HTTPサーバはエラーを起こします。

リソースの操作

前述で、catsリソースを取得するためのエンドポイントを定義しました。新しいレコードを作成するエンドポイントも同時に提供したいときには、POSTを活用しましょう。
cats.controller.ts
import { Controller, Get, Post } from '@nestjs/common'
@Controller('cats')
export class CatsController {
@Post()
create(): string {
return 'This action adds a new cat'
}
@Get()
findAll(): string {
return 'This action returns all cats'
}
}
これは簡単です。該当の関数の上にHTTPメソッドのデコレータを置くだけでいいのです。他にも、以下のようなメソッドに対応しています。
  • @Put()
  • @Delete()
  • @Patch()
  • @Options()
  • @Head()
  • @All()

ルートパスの設定

NestJSはパターンベースのルーティング設定もサポートされています。例えば、アスタリスク(*)は任意の文字列の組み合わせにマッチします。
@Get('ab*cd')
findAll() {
return 'This route uses a wildcard'
}
ab*cdルートパスは、abcdad_cdabecdなどにマッチします。ルートパスには?+*()などという文字列が使用でき、これらは正規表現に対応するセットになっています。ハイフン(-)やドット(.)は、文字列ベースのパスでは文字通りに解釈されます。

ステータスコード

前述の通り、デフォルトではレスポンスステータスコードは常に200ですが、POSTリクエストだけは例外で201になります。この挙動は、ハンドラレベルで@HttpCode(....)デコレータを追加することで簡単に変更できます。
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat'
}
メモ
@nestjs/commonパッケージからHttpCodeをインポートしてください。

ヘッダー(Header)

独自のレスポンスヘッダを指定する際には、@Header()デコレータを使用するか、あるいはライブラリ固有のレスポンスオブジェクトを使用します。
@Post()
@Header('Cache-Control', 'none')
create() {
return 'This action adds a new cat'
}
メモ
@nestjs/commonパッケージからHeaderをインポートしてください。

リダイレクト

レスポンスを特定のURLにリダイレクトするには、@Redirect()デコレータを使うか、ライブラリ固有のレスポンスオブジェクト(直接res.redirect()を呼ぶ)を使うかのどちらかになります。
@Redirect()は2つの引数を取ります。それはurlstatusCodeです。デフォルトのstatusCodeの値は302に設定されています。(第二引数を設定しない場合)
@Get()
@Redirect('https://nestjs.com', 301)
HTTPのステータスコードやリダイレクトURLを動的に決定したいこともあるでしょう。これを行うには、ルートハンドラーメソッドからオブジェクトを形で返します。(いわゆるJSON形式)
{
"url": string,
"statusCode": number
}
戻り値は、@Redirect()デコレータに渡されたすべての引数を上書きします。以下に例を示します。
@Get('docs')
@Redirect('https://docs.nestjs.com', 302)
getDocs(@Query('version') version) {
if (version && version === '5') {
return { url: 'https://docs.nestjs.com/v5/' }
}
}

ルートパラメータ

リクエストの一部として動的なデータを受け取る必要がある場合、静的なパスを持つルートは機能しません。(例えば、GET /cats/1ではid1の猫を取得する)パラメータ付きのルートを定義する際には、ルートのパスにルートパラメータのトークン(Token)を追加して、リクエストURLのその一にある動的な値を取り込むようにすればいいのです。
以下のサンプルプログラムの@Get()デコレータの例のルートパラメータのトークンはこの使い方を示ししています。このようにして宣言したルートパラメータには、@Param()デコレータを使ってアクセスできます。
@Get(':id')
findOne(@Param() params): string {
console.log(params.id)
return `This action returns a #${params.id} cat`
}
メソッドパラメータを装飾するために@Param()を使用し、メソッド本体の中でその装飾されたメソッドパラメータのプロパティとしてルートパラメータを利用できるようにします。上記のコードに見られるように、params.idを参照することで、idパラメータにアクセスできます。
また、特定のパラメータトークンをデコレータに渡すと、そのルートパラメータをメソッド本体の中で直接名前で参照することもできます。
メモ
@nestjs/commonからParamをインポートしてください。
// ルーティングでIDを指定する際
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns a #${id} cat`;
}

サブドメインルーティング

Controllerデコレータにhostオプションを指定すると、受け取ったリクエストのHTTPホストが特定の値に一致することを要求できます。
// Controllerデコレータ内に引数hostでドメインを指定することで、管理者ページみたいなものを作れる。
@Controller({ host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
注意 Fastifyはネストされたルーティングをサポートしていないので、サブドメインルーティングを使うにはデフォルトのExpressアダプタを使う必要があります。
ルートパスと同様に、hostsオプションでもトークンを使用してホスト名のその位置の動的な値を所得できます。以下の@Controller()デコレータの例にあるホストパラメータトークンは、この使い方を示しています。この方法で宣言したホストパラメータには、@HostParam()デコレータを使用してアクセスすることもできます。
@Controller({ host: ':account.example.com' })
export class AccountController {
@Get()
getInfo(@HostParam('account') account: string) {
return account
}
}