バリデーションレスポンスをカスタマイズする[NestJS]
やりたいこと
NestJS の Web API は class-validator を使ってリクエストを検証できる。
そして、そこで引っかかった項目をまとめて 400 のエラーを返してくれる。
こんな感じ。
{
"statusCode": 400,
"message": [
"each value in {field} must be a valid enum value"
],
"error": "Bad Request",
}
このフォーマットを好きな形に変更したい。
やりかた
このレスポンスは class-validation が生成したクラスインスタンスからエラーメッセージ取り出して Nest の Exception クラスを作成することによって作られている。
そして、それは ValidationPipe の中で行われている。
なので、ここの実装をいじってあげることで実現できる。
ValidationPipe ってなに
main.ts のここに書かれてるやつ。
app = moduleFixture.createNestApplication();
app.useGlobalPipes(new ValidationPipe({ transform: true }));
await app.init();
実装する
ValidationPipe を拡張する形で作成。
(private なプロパティが多かったので、この実装方法はあまり想定されていないのかも?)
使っている BadRequestException は独自に実装したもので、ここでレスポンスの形を決めている。
BadRequestException の実装については NestJS でエラーレスポンスをカスタマイズしてみる ここで書いている。
import { ValidationPipe, HttpStatus } from '@nestjs/common';
import { ValidationError } from 'class-validator';
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
import { iterate } from 'iterare';
import { BadRequestException } from 'src/exception/badRequest.exception';
export class CustomValidationPipe extends ValidationPipe {
createExceptionFactory() {
return (validationErrors: ValidationError[] = []) => {
if (this.isDetailedOutputDisabled) {
return new HttpErrorByCode[this.errorHttpStatusCode]();
}
const errors = this.flattenValidationErrorsExtends(
validationErrors,
);
// Bad Request 以外でも使いたければここらへんの実装をいじる
if (this.errorHttpStatusCode === HttpStatus.BAD_REQUEST)
return new BadRequestException(errors);
return new HttpErrorByCode[this.errorHttpStatusCode](errors);
};
}
private flattenValidationErrorsExtends(
validationErrors: ValidationError[],
): string[] {
return iterate(validationErrors)
.map(error => this.mapChildrenToValidationErrorsExtends(error))
.flatten()
.filter(item => !!item.constraints)
.map(item => item.constraints && Object.values(item.constraints))
.flatten()
.toArray()
.filter(
(item): item is Exclude<typeof item, undefined> =>
item !== undefined,
);
}
private mapChildrenToValidationErrorsExtends(error: ValidationError) {
if (!(error.children && error.children.length)) {
return [error];
}
const validationErrors: ValidationError[] = [];
for (const item of error.children) {
if (item.children && item.children.length) {
validationErrors.push(
...this.mapChildrenToValidationErrorsExtends(item),
);
}
validationErrors.push(
this.prependConstraintsWithParentPropExtends(error, item),
);
}
return validationErrors;
}
private prependConstraintsWithParentPropExtends(
parentError: ValidationError,
error: ValidationError,
) {
const constraints: { [key: string]: string } = {};
for (const key in error.constraints) {
constraints[
key
] = `${parentError.property}.${error.constraints[key]}`;
}
return Object.assign(Object.assign({}, error), { constraints });
}
}
使ってみる
main.ts
こんな感じで使ってあげれば、指定した形でレスポンスが返ってくる。
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { Logger, INestApplication } from '@nestjs/common';
import { Config } from './app.config';
import { CustomValidationPipe } from 'src/presentation/pipe/customValidation.pipe';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new CustomValidationPipe({
transform: true,
}),
);
await app.init();
await app.listen(3000);
}
bootstrap();
Author And Source
この問題について(バリデーションレスポンスをカスタマイズする[NestJS]), 我々は、より多くの情報をここで見つけました https://qiita.com/tktcorporation/items/5d70e4dde85ae3b6eeda著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .