Controllerとは
NestJSにおける
Controller
は、送られてくるリクエストを処理してレスポンスをクライアントに返す枠割を担っています。Controller
の目的は、アプリケーション内の特定のリクエストを 受け取ることです。ルーティングは、どのController
がどのリクエストを受信するのかを制御します。大半の場合、それぞれのController
は複数のルートを持ち、異なるルートは異なるアクションを実行できます。基本的な
Controller
を作成するために、class
やdecorator
を活用します。メモ
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のレスポンス処理は簡単になります。
ライブラリ固有のレスポンスオブジェクト使用します。これは、メソッドの中に@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
ルートパスは、abcd
、ad_cd
、abecd
などにマッチします。ルートパスには?
、+
、*
や()
などという文字列が使用でき、これらは正規表現に対応するセットになっています。ハイフン(-
)やドット(.
)は、文字列ベースのパスでは文字通りに解釈されます。前述の通り、デフォルトではレスポンスステータスコードは常に200ですが、POSTリクエストだけは例外で201になります。この挙動は、ハンドラレベルで
@HttpCode(....)
デコレータを追加することで簡単に変更できます。@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat'
}
メモ
@nestjs/common
パッケージからHttpCode
をインポートしてください。独自のレスポンスヘッダを指定する際には、@Header()デコレータを使用するか、あるいはライブラリ固有のレスポンスオブジェクトを使用します。
@Post()
@Header('Cache-Control', 'none')
create() {
return 'This action adds a new cat'
}
メモ
@nestjs/common
パッケージからHeader
をインポートしてください。レスポンスを特定のURLにリダイレクトするには、
@Redirect()
デコレータを使うか、ライブラリ固有のレスポンスオブジェクト(直接res.redirect()
を呼ぶ)を使うかのどちらかになります。@Redirect()は2つの引数を取ります。それは
url
とstatusCode
です。デフォルトの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
}
}
Last modified 9mo ago