You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中如何为@IsNotIn校验器抛出元数据信息

问题描述

我有如下NestJS DTO:

import { IsEmail, IsNotEmpty, IsNotIn } from 'class-validator';
import { AppService } from './app.service';
const restrictedNames = ['Name Inc', 'Acme Inc'];
class DTO {
  @IsNotEmpty()
  name: string;
  @IsEmail()
  email: string;

  @IsNotEmpty()
  @IsNotIn(restrictedNames)
  orgName: string;
}

我配置了全局ValidationPipe并自定义异常过滤器,返回包含校验失败详情的错误信息:

app.useGlobalPipes(
new ValidationPipe({
  exceptionFactory: (validationErrors: ValidationError[] = []) => {
    console.log(validationErrors);
    return new BadRequestException({
      statusCode: HttpStatus.BAD_REQUEST,
      message: validationErrors.reduce((acc, error) => {
        acc[error.property] = Object.keys(error.constraints).map(
          (failed) => ({
            failedValidation: failed,
            message: error.constraints[failed],
          }),
        );
        return acc;
      }, {}),
      error: 'validation',
    });
  },
}),

当前校验失败时返回的错误示例:

{"statusCode":400,"message":{"email":[{"failedValidation":"isEmail","message":"email must be an email"}],"orgName":[{"failedValidation":"isNotIn","message":"orgName should not be one of the following values: Name Inc, Acme Inc"}]},"error":"validation"}

但我希望@IsNotIn校验失败时,能把禁用的关键词以单独字段返回,期望返回格式如下:

{"statusCode":400,"message":{"email":[{"failedValidation":"isEmail","message":"email must be an email"}],"orgName":[{"failedValidation":"isNotIn","message":"orgName should not be one of the following values: Name Inc, Acme Inc", "data":{"reservedKeywords":["Name Inc","Acme Inc"]}}]},"error":"validation"}

现有异常过滤器无法获取装饰器元数据中的约束值,请问如何修改异常过滤器实现这个需求?

解决方案

要实现这个需求,你需要开启class-validator的上下文参数传递,然后针对isNotIn校验器提取约束值:

修改后的异常过滤器代码如下:

import { ValidationError } from 'class-validator';
import { BadRequestException, HttpStatus, ValidationPipe } from '@nestjs/common';

app.useGlobalPipes(
  new ValidationPipe({
    exceptionFactory: (validationErrors: ValidationError[] = []) => {
      return new BadRequestException({
        statusCode: HttpStatus.BAD_REQUEST,
        message: validationErrors.reduce((acc, error) => {
          acc[error.property] = Object.keys(error.constraints).map((failed) => {
            const errorDetail = {
              failedValidation: failed,
              message: error.constraints[failed],
            };
            // 针对isNotIn校验器提取禁用关键词列表
            if (failed === 'isNotIn') {
              const reservedKeywords = error.context?.constraints[0];
              if (reservedKeywords) {
                errorDetail['data'] = { reservedKeywords };
              }
            }
            return errorDetail;
          });
          return acc;
        }, {}),
        error: 'validation',
      });
    },
    // 开启context选项,才能获取校验器的参数元数据
    validationError: {
      target: false, // 可选:关闭返回目标类信息
      value: false, // 可选:关闭返回字段值
      context: true, // 关键配置:开启后可拿到校验器传入的参数
    },
  }),
);

核心说明

  1. 开启context配置:必须在validationError中设置context: true,class-validator才会把@IsNotIn传入的restrictedNames等参数存入ValidationError的context属性中。
  2. 针对性处理校验器:遍历约束失败项时,判断当前失败类型为isNotIn,就从error.context.constraints[0]中取出禁用关键词列表,添加到data.reservedKeywords字段。
  3. 兼容性保障:该修改仅对isNotIn校验器生效,不会影响其他校验器的错误返回格式。

内容的提问来源于stack exchange,提问作者Vishal Tyagi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:43:18