在 NestJS 中抛出与 `class-validator` 相同的错误格式
Posted
技术标签:
【中文标题】在 NestJS 中抛出与 `class-validator` 相同的错误格式【英文标题】:Throw same error format as `class-validator` in NestJS 【发布时间】:2020-06-01 20:36:35 【问题描述】:让我们在 NestJS 项目中拥有这个控制器:
@Post('resetpassword')
@HttpCode(200)
async requestPasswordReset(
@Body() body: RequestPasswordResetDTO,
): Promise<boolean>
try
return await this.authService.requestPasswordReset(body);
catch (e)
if (e instanceof EntityNotFoundError)
// Throw same exception format as class-validator throwing (ValidationError)
else throw e;
Dto 定义:
export class RequestPasswordResetDTO
@IsNotEmpty()
@IsEmail()
public email!: string;
当this.authService.requestPasswordReset(body);
抛出EntityNotFoundError
异常时,我想以ValidationError
格式(属性、值、约束等)抛出错误。
如何手动创建此错误?当class-validator
的 DTO 验证失败时,就会抛出这些错误。这些可以只是静态验证,而不是异步数据库验证。
所以最终的API响应格式应该是例如:
"statusCode": 400,
"error": "Bad Request",
"message": [
"target":
"email": "not@existing.email"
,
"value": "not@existing.email",
"property": "email",
"children": [],
"constraints":
"exists": "email address does not exists"
]
我需要它有一致的错误处理:)
【问题讨论】:
您可以创建一个异步验证器。请参阅此处的示例:github.com/typestack/… 【参考方案1】:将ValidationPipe
添加到您的应用时,请提供自定义exceptionFactory
:
app.useGlobalPipes(
new ValidationPipe(
exceptionFactory: (validationErrors: ValidationError[] = []) =>
return new BadRequestException(validationErrors);
,
)
);
这应该是您获得预期结果所需的全部内容。
为了比较,你可以查看原始 NestJS 版本here。
【讨论】:
我认为 NestJ 曾经一度总是返回 ValidationErrors,但在最新版本中,它们默认使用自己的异常过滤器。我可能是错的,但我确实有一次遇到了一系列 ValidationErrors。那或者我在某处更改了配置。 你如何访问这些值? 不完全确定你在问什么,@John。在异常工厂箭头函数中,来自class-validator
的原始验证错误可以在validationErrors
变量中访问。【参考方案2】:
您可以使用Exception Filter 来创建针对该异常的自定义响应 首先我们定义异常过滤器:
import ExceptionFilter, Catch, ArgumentsHost, HttpException from '@nestjs/common';
import Request, Response from 'express';
// import EntityNotFoundError from 'wherever';
@Catch(EntityNotFoundError)
export class EntityNotFoundExceptionFilter implements ExceptionFilter
catch(exception: HttpException, host: ArgumentsHost)
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json(
"statusCode": 400,
"error": "Bad Request",
"message": [
"target": ,
"property": "email",
"children": [],
"constraints":
"isEmail": "email must be an email"
,
// other field exceptions
]
);
然后回到你的控制器,你使用过滤器:
// ...
import EntityNotFoundExceptionFilter from 'its module';
// ...
@Post('resetpassword')
@HttpCode(200)
@UseFilters(EntityNotFoundExceptionFilter)
async requestPasswordReset(
@Body() body: RequestPasswordResetDTO
): Promise<boolean>
return await this.authService.requestPasswordReset(body);
这应该可以正常工作。
【讨论】:
EntityNotFoundError
与 HttpException
不同,您的示例将在 exception.getStatus()
上失败
这很糟糕。您需要为类验证器中的每条错误消息创建一个自定义异常过滤器。这就像 30 多个异常过滤器。不用了!【参考方案3】:
我们可以取回class-validator
抛出的异常响应并设置为响应,
import
ArgumentsHost,
BadRequestException,
Catch,
ExceptionFilter
from '@nestjs/common';
@Catch()
export class ValidationFilter < T > implements ExceptionFilter
catch (exception: T, host: ArgumentsHost)
if (exception instanceof BadRequestException)
const response = host.switchToHttp().getResponse();
response.status(exception.getStatus())
.json(exception.getResponse());
控制器应该看起来,
@Post('create')
@UsePipes(ValidationPipe)
@UseFilters(ValidationFilter)
async create(@Body() body: CreateDto)
【讨论】:
以上是关于在 NestJS 中抛出与 `class-validator` 相同的错误格式的主要内容,如果未能解决你的问题,请参考以下文章