created: 2021-05-02T04:11:30.000Z

NestJS/class-transformer でPOSTされなかったパラメータにデフォルトを設定する

前回までのあらすじ

文字列で渡ってきた "2011-01-01 12:34:56" という文字列を new Date("2011-01-01 12:34:56") された状態で扱うことはできるようになったが、今度はこれにデフォルト値を入れた状態でコントローラが受け取るための方法。

たとえば、expireAt というフィールドがあって、これが null でPOSTされてきたときに二ヶ月後のDateが入った状態で処理を開始したい場合はこんなコードを書けばよい。

import { addMonths } from 'date-fns';
import { Type, Transform } from 'class-transformer';
export class CreateSampleDto {
  @IsDate()
  @IsNotEmpty()
  @Type(() => Date)
  @Transform(({ value }) => value || addMonths(new Date(), 1), {
    toClassOnly: true,
  })
  expireAt: Date;
}

Caveat

NestJS の ValidationPipeundefined だったフィールドは処理してくれないので、falsyな値をつけてPOSTしないと期待通りに動作しない。

つまり、この値をPOSTした場合は期待通り二ヶ月後の日付が入るが

{"id": 1, "expireAt": null}
{"id": 1, "expireAt": "0"}

こんな値をPOSTした場合は、そもそもデフォルト値を入れるための処理が呼ばれない。

{"id": 1}
{"id": 1, "expireAt": undefined}

意図せぬ値がDBに入らないように class-validatorIsNotEmpty を使うと、undefined をPOSTした場合は弾いて、null をPOSTした場合は期待通りに動作するようになる。IsNotEmptyTransform よりも後に呼ばれるようだ。

苦しい感じでなんとかしているが、クライアント側からするとよくわからない仕様なので本当は undefined を投げられた場合もなんとかしたい。

ユーザーの問題解決とプロダクトの成功を導く エンジニアのためのドキュメントライティング
[ad] ユーザーの問題解決とプロダクトの成功を導く エンジニアのためのドキュメントライティング
ジャレッド・バーティ, ザッカリー・サラ・コ―ライセン (単行本)