😺

NestJS で ストロングパラメータ- みたいなことをしたい

2022/02/02に公開

背景

DTOでValidationを実装したはいいけど、DTOで定義していないパラメータを除外したい。
Railsのストロングパラメーターpermit にあたる機能を NestJS で探していたのですが、名称が違うのでここで紐付けておきます。

環境

  • @nestjs/core (v8.0.0)

やりたいこと

Railsのストロングパラメーターpermit を NestJS でも実装したい。

例えば、以下のようなリクエストを行ったとします。

// POST localhost:3000
{
    "id": "1",
    "age": 29,
    "name": "bob"
}

上記リクエストのBodyから受け取りたいパラメータを validation しつつ、validation を通過したパラメータだけサーバーサイド側で受け取り、それ以外は除外したい。

上記でvalidationを行うパラメータはid,ageだけの場合、以下のようになるイメージです。

※ Railsでいうと下記のような設定になるはずです。

app/controllers/app_controller.rb
params.permit(:id, :age)

すると、paramsから取得できるパラメーターは以下のようになるはずです。

// POST localhost:3000
{
    "id": "1",
    "age": 29,
}

nameは許可(permit)されていないので除外されています。

なぜストロングパラメータを使いたいのか

  1. validationを通過していないパラメータを除外したい
  2. フロントエンドでのパラメーター選別作業が面倒なため

サーバーサイド側でvalidationついでに必要ないパラメーターを除外したほうが、セキュリティ的にも安全で、フロントエンドでリクエスト時にパラメーターを選別が不要になり一石二鳥です🐔

Railsでは実装方法がRailsチュートリアルなどで、ストロングパラメータを扱うので一般的ですが、NestJSの場合どうするのかすぐ出てきませんでした。

ドキュメントを漁ると、NestJSの場合、validationとパラメーターの除外はDTOというファイルと、whitelisttrueにすることで実装することができました。
Railsのストロングパラメーターpermitは、NestJSではstripping-propertiesと呼ばれているのですね。

whitelisttrue に設定

グローバルに設定したい場合は下記のように, bootstrap上で定義します。

main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
+  app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
  await app.listen(3000);
}
bootstrap();

個別にメソッド単位で定義する場合は、controllerやresolver単位で設定できます。

app.controller.ts
import { Body, Controller, Get, Param, Post, Query, UsePipes, ValidationPipe } from '@nestjs/common';
import { GreetingDto } from './greeting-dto';

@Controller()
export class AppController {
  @Post()
+ @UsePipes(new ValidationPipe({ whitelist: true }))
  getGreeting(@Body() greeting: GreetingDto) {
    return greeting;
  }
}

注意

whitelistを使用するときは、class-validatorclass-transformerをinstallする必要があります。まだ追加されていないプロジェクトであれば追加してください。

npm i class-validator class-transformer

POSTの場合

さきほど、idagevalidationを行うDTOファイルを作成しvalidationを行います。

greeting-dto.ts
import { Transform } from 'class-transformer';
import { IsNumber, IsNumberString, IsOptional } from 'class-validator';

export class GreetingDto {
  @IsNumberString()
  id: string;

  @IsNumber()
  age: number;
}

上記のDTOファイルをgetGreetingの型に使用すると、NestJSがvalidationを行う設定ができました。

app.controller.ts
import { Body, Controller, Get, Param, Post, Query, UsePipes, ValidationPipe } from '@nestjs/common';
import { GreetingDto } from './greeting-dto';

@Controller()
export class AppController {
  @Post()
  @UsePipes(new ValidationPipe({ whitelist: true }))
  getGreeting(@Body() greeting: GreetingDto) {
    return greeting;
  }
}

whitelistfalse(デフォルト) のとき

POST localhost:3000
body
{
    "id": "1",
    "age": 29,
    "name": "bob"
}
response
{
  "id": "1",
  "age": 29,
  "name": "bob"
}

whitelisttrue のとき

POST localhost:3000
body
{
  "id": "1",
  "age": 29,
  "name": "bob"
}
response
{
  "id": "1",
  "age": 29
}

ちゃんと、DTOで定義されていないパラメータは除外されました。

参考

NestJS Validation stripping-properties

GitHubで編集を提案

Discussion