😔

@Transformが2回呼ばれる

2022/12/08に公開

なぜ@Transformが2回呼ばれるのか分かりません。

NestJSにおいて、クライアントからのQueryStringをValidationしtransformしようとしました。

環境

    "@nestjs/common": "^9.0.0",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.13.2",

controller.ts

  @Get(':id')
  async getUser(
    @Req() req: Request,
    @Param('id', ParseIntPipe) id: number,
    @Query() queryParams: queryDto,
  ) {
  中略
  }

queryDto

import { IsBoolean, IsOptional } from 'class-validator';
import { Transform } from 'class-transformer';
import { BadRequestException } from '@nestjs/common';

export class queryDto {
  @IsOptional()
  @Transform(({ value }) => {
    console.log('call @Transform');
    console.log(typeof value);
    console.log(value);
    if (typeof value === 'boolean') {
      return value;
    }
    if (value === 'true') {
      return true;
    }
    if (value === 'false') {
      return false;
    }
    throw new BadRequestException('active is only true or false');
  })
  @IsBoolean()
  readonly active?: boolean;

  constructor() {
    console.log('call constructor');
  }
}

http://localhost:3000/user/1?active=true
にアクセスすると、コンソールに以下のように出力されます。

call constructor
call @Transform
string
true
call @Transform
boolean
true

@Transformが2回呼ばれます。
最初の1回目では、valueに文字列trueがセットされて、booleanのtrueが返ります。
この後、おそらく、booleanのtrueがvalueにセットされて、もう一度@Transformが動いているようです。
なぜなのか分かりません…

queryDtoの中で、

    if (typeof value === 'boolean') {
      return value;
    }

が書いてあります。
クライアントからくるvalueは必ず文字列なので、必要ないのですが…2回目に@Transformが呼ばれたとき、valueはboolean型なので、これを書かないとthrow new BadRequestExceptionにいってしまいます…

Discussion