Dev Study
NestJS コース

30. カスタムデコレータ — パラメータデコレータを自作する

NestJS では createParamDecorator を使って、@Param や @Body のような引数デコレータを自作できます。createParamDecorator に (data, ctx) => ... のファクトリ関数を渡すとデコレータが作られ、ctx.switchToHttp().getRequest() でリクエストを取り出して、必要な値を返すように書きます。代表例は、認証ガードが request.user に入れた値を取り出す @User() です。

実務では、各ハンドラで毎回 @Req() req: Request を受け取って req.user と書く代わりに、@User() user のように意図の明確な1つのデコレータへ集約するために使います。第1引数の data を活かして @User("id") のようにプロパティ名を渡し、特定のフィールドだけ取り出す形にするのも定番です。

つまずきポイントは、デコレータは値を取り出すだけの薄い部品に徹することです。request.user を埋めるのはあくまで既習の認証ガードの仕事で、デコレータ側で認証処理を行うわけではありません。ガードが動いていなければ user は undefined のままなので、両者の役割分担を意識しましょう。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import {
  createParamDecorator, ExecutionContext,
  Controller, Get, UseGuards,
} from "@nestjs/common";

// 認証ガードが request.user に入れた値を取り出すデコレータ
export const User = createParamDecorator(
  (data: string | undefined, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;
    // @User("id") のように渡せば特定のプロパティだけ返す
    return data ? user?.[data] : user;
  },
);

@Controller("profile")
export class ProfileController {
  @Get()
  @UseGuards(AuthGuard) // これが request.user を埋める前提
  me(@User() user: { id: string; name: string }) {
    return user; // req.user をそのまま受け取れる
  }
}
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗