NestJS中class-validator无法识别price[$gte]查询参数键的解决方法
解决NestJS中class-validator无法识别
price[$gte]类查询参数键的问题 class-validator默认无法直接识别price[$gte]这类带特殊语法的查询参数键——这类参数属于扁平化的MongoDB风格查询语法,而class-validator更适配嵌套对象结构的验证。以下是几种可行的解决办法:
方法一:自定义参数转换器转换结构
通过class-transformer的@Transform装饰器实现自定义转换器,将扁平化的查询参数转换为嵌套对象,让class-validator可以正常验证:
1. 定义转换器函数
import { Transform } from 'class-transformer'; // 转换MongoDB风格的扁平化查询参数为嵌套对象 const ParseMongoQuery = () => Transform(({ value }) => { const result = {}; for (const key in value) { // 匹配`xxx[$yyy]`格式的键 const match = key.match(/^(\w+)\[\$(\w+)\]$/); if (match) { const [parentKey, operator] = match.slice(1); result[parentKey] = result[parentKey] || {}; // 转换为数字类型(可根据实际需求调整类型) result[parentKey][`$${operator}`] = Number(value[key]); } else { result[key] = value[key]; } } return result; });
2. 在DTO中使用转换器
import { IsOptional, IsObject, IsNumber } from 'class-validator'; import { Type } from 'class-transformer'; // 定义嵌套的价格验证规则 class PriceQuery { @IsOptional() @IsNumber() $gte?: number; @IsOptional() @IsNumber() $lte?: number; } class ExampleDto { @IsOptional() @IsObject() @Type(() => PriceQuery) // 指定嵌套类类型 @ParseMongoQuery() price?: PriceQuery; }
请求中的price[$gte]会被自动转换为price.$gte,class-validator即可正常验证嵌套对象的属性。
方法二:控制器内手动转换参数结构
在控制器中先手动处理查询参数的结构转换,再传入验证管道:
import { Controller, Get, Query, BadRequestException } from '@nestjs/common'; import { ExampleDto } from './example.dto'; import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; @Controller('examples') export class ExampleController { @Get() async getExamples(@Query() rawQuery: Record<string, any>) { // 转换扁平化参数为嵌套对象 const transformedQuery = {}; for (const key in rawQuery) { const match = key.match(/^(\w+)\[\$(\w+)\]$/); if (match) { const [parentKey, operator] = match.slice(1); transformedQuery[parentKey] = transformedQuery[parentKey] || {}; transformedQuery[parentKey][`$${operator}`] = Number(rawQuery[key]); } else { transformedQuery[key] = rawQuery[key]; } } // 手动验证转换后的参数 const dto = plainToInstance(ExampleDto, transformedQuery); const errors = await validate(dto); if (errors.length > 0) { throw new BadRequestException('参数验证失败'); } return dto; } }
方法三:使用@Expose映射参数键
通过class-transformer的@Expose指定参数键的映射关系,配合@Transform直接转换属性值,适合单个参数的场景:
import { IsOptional, IsObject, IsNumber } from 'class-validator'; import { Expose, Transform, Type } from 'class-transformer'; class PriceQuery { @IsOptional() @IsNumber() $gte?: number; } class ExampleDto { @IsOptional() @IsObject() @Type(() => PriceQuery) @Expose({ name: 'price[$gte]' }) // 指定原始参数键名 @Transform(({ obj }) => ({ $gte: obj['price[$gte]'] ? Number(obj['price[$gte]']) : undefined, })) price?: PriceQuery; }
内容的提问来源于stack exchange,提问作者Desalutar
相关产品推荐
相关产品推荐

