[NestJS]バリデーションエラーをカスタマイズする
デフォルトのバリデーションエラーレスポンス
https://docs.nestjs.com/techniques/validation#using-the-built-in-validationpipe を参考にしつつ以下のコードを考えてみます。
import {
Body,
Controller,
Post,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { AppService } from './app.service';
import { CreateUserDto } from './create-user-dto';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post()
@UsePipes(new ValidationPipe())
postHello(@Body() createUserDto: CreateUserDto) {
console.log('createUserDto', createUserDto);
return this.appService.getHello();
}
}
import { IsEmail, IsNotEmpty } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsNotEmpty()
password: string;
}
この状態でBodyを空でリクエストすると以下のレスポンスとなります。
{
"message": [
"email must be an email",
"password should not be empty"
],
"error": "Bad Request",
"statusCode": 400
}
このレスポンスをカスタマイズしてみます。
カスタマイズ方法
ValidationPipeのexceptionFactoryを使います。
import {
BadRequestException,
Body,
Controller,
Post,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { AppService } from './app.service';
import { CreateUserDto } from './create-user-dto';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Post()
@UsePipes(
new ValidationPipe({
exceptionFactory: () => {
return new BadRequestException({
custom: 'message1',
hoge: 'message2',
});
},
}),
)
postHello(@Body() createUserDto: CreateUserDto) {
console.log('createUserDto', createUserDto);
return this.appService.getHello();
}
}
するとレスポンスは以下のようにBadRequestExceptionのコンストラクタに渡したオブジェクトとなります。
{
"custom": "message1",
"hoge": "message2"
}
ちなみに、exceptionFactoryは引数を取ることもできます。
@UsePipes(
new ValidationPipe({
exceptionFactory: (error) => {
console.log('error', error);
return new BadRequestException(error);
},
}),
)
今回の場合のerrorの中身は
[
{
"target": {},
"property": "email",
"children": [],
"constraints": {
"isEmail": "email must be an email"
}
},
{
"target": {},
"property": "password",
"children": [],
"constraints": {
"isNotEmpty": "password should not be empty"
}
}
],
このようになっているのでここからかいつまんでエラー内容をレスポンスに含めることもできます。
コードを追ってみる
ValidationPipeのコードは以下です。
バリデーションエラーがあった場合は ここで例外を投げています。
this.exceptionFactory(errors);は何かというと、
ValidationPipeのコンストラクタでセットしているものになります。
これが以下のようにオプションで設定したexceptionFactoryとなります。
@UsePipes(
new ValidationPipe({
exceptionFactory: () => {
return new BadRequestException({
custom: 'message1',
hoge: 'message2',
});
},
}),
)
ちなみに、オプションでexceptionFactoryをセットしなかった場合はデフォルトのthis.createExceptionFactory()となります。
HttpErrorByCode[this.errorHttpStatusCode]というのは、
ここで、HttpStatusごとにExceptionを割り当てているファイルがあり、
ValidationPipeの場合はthis.errorHttpStatusCodeはデフォルトでBAD_REQUESTとなるので、
BadRequestExceptionを投げているということになります。
例外が発生した後は、NestJSの例外を拾うレイヤーでレスポンスが作られます。
今回は以下のようにBadRequestExceptionにオブジェクトを渡しているため、
@UsePipes(
new ValidationPipe({
exceptionFactory: () => {
return new BadRequestException({
custom: 'message1',
hoge: 'message2',
});
},
}),
)
渡したオブジェクトがそのままレスポンスとなる形となっています。
サンプルプロジェクト
おわりに
少しでも参考になれば幸いです。
よかったらいいね等お願いします!
Discussion