[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