NestJS class-validator如何根据其他属性动态调整属性校验规则
实现方案
这种依赖同个DTO下其他字段值的动态校验,用class-validator自带的类级自定义校验就能实现,不需要额外依赖,也不用写绕路的全局管道逻辑,实现步骤如下:
- 首先移除
name字段上写死的@MaxLength(1000)装饰器,保留@IsString()做基础类型校验即可。 - 先维护一份分类和对应name最大长度的映射表,后续调整规则、新增分类直接改这份配置就行:
// 各分类对应的name长度上限,未配置的分类默认兜底1000字符 const CATEGORY_NAME_MAX_LENGTH: Record<Category, number> = { [Category.x]: 500, [Category.y]: 700, // 其他分类规则直接追加在这里 }
- 写一个轻量的校验规则类,直接挂在DTO类上即可,不需要单独抽离到公共文件:
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, Validate, IsEnum, IsString, } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; @ValidatorConstraint({ name: 'dynamicNameLength', async: false }) class DynamicNameLengthConstraint implements ValidatorConstraintInterface { validate(_: any, args: ValidationArguments) { const dto = args.object as YourBizDto; // 替换为你实际的DTO类名 const limit = CATEGORY_NAME_MAX_LENGTH[dto.category] ?? 1000; return typeof dto.name === 'string' && dto.name.length <= limit; } defaultMessage(args: ValidationArguments) { const dto = args.object as YourBizDto; const limit = CATEGORY_NAME_MAX_LENGTH[dto.category] ?? 1000; return `name字段最大长度不能超过${limit}个字符`; } } // 类上挂载动态校验规则 @Validate(DynamicNameLengthConstraint) export class YourBizDto { @ApiProperty() @IsEnum(Category) category: Category; @ApiProperty({ description: '名称长度随分类动态限制:x类最长500字符,y类最长700字符' }) @IsString() name: string; }
说明
class-validator执行类级校验时,所有属性已经完成基础赋值和格式校验,如果传入的category本身不是合法枚举值,会先抛出category的校验错误,不会走到name长度判断逻辑,不需要额外写判空、值合法性判断。
这种写法校验逻辑完全和DTO绑定,其他业务位置复用这个DTO时不需要额外加处理,后续如果要扩展动态规则(比如不同分类下name的正则校验、必填规则变化),直接在这个校验类里补逻辑即可,维护成本很低。
内容的提问来源于stack exchange,提问作者fraktus
相关产品推荐
相关产品推荐

