NestJS嵌套DTO类验证失败及Swagger Schema异常求助
问题分析与解决方案
问题根源
- Swagger Schema显示异常:父DTO中的数组字段
originDestinations和travelers仅用@ApiProperty()装饰,未明确指定数组内的嵌套类型,导致Swagger默认解析为字符串数组。 - Postman验证错误:请求体未按嵌套结构传递数据,或class-transformer未正确将JSON转换为DTO实例,触发class-validator的字段校验规则。
修正后的DTO代码
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { Type } from "class-transformer"; import { IsNotEmpty, IsArray, ValidateNested, IsDateString, MinLength, MaxLength, IsEnum } from "class-validator"; // 定义枚举类型,增强类型安全性 export enum TravelerType { ADULT = "ADULT", CHILD = "CHILD", SENIOR = "SENIOR", YOUNG = "YOUNG", HELD_INFANT = "HELD_INFANT", SEATED_INFANT = "SEATED_INFANT", STUDENT = "STUDENT" } export enum FareOption { STANDARD = "STANDARD", INCLUSIVE_TOUR = "INCLUSIVE_TOUR", SPANISH_MELILLA_RESIDENT = "SPANISH_MELILLA_RESIDENT", SPANISH_CEUTA_RESIDENT = "SPANISH_CEUTA_RESIDENT", SPANISH_CANARY_RESIDENT = "SPANISH_CANARY_RESIDENT", SPANISH_BALEARIC_RESIDENT = "SPANISH_BALEARIC_RESIDENT", AIR_FRANCE_METROPOLITAN_DISCOUNT_PASS = "AIR_FRANCE_METROPOLITAN_DISCOUNT_PASS", AIR_FRANCE_DOM_DISCOUNT_PASS = "AIR_FRANCE_DOM_DISCOUNT_PASS", AIR_FRANCE_COMBINED_DISCOUNT_PASS = "AIR_FRANCE_COMBINED_DISCOUNT_PASS", AIR_FRANCE_FAMILY = "AIR_FRANCE_FAMILY", ADULT_WITH_COMPANION = "ADULT_WITH_COMPANION", COMPANION = "COMPANION" } class Travelers { @ApiProperty({ enum: TravelerType }) @IsEnum(TravelerType) travelerType: TravelerType; @ApiProperty({ enum: FareOption, isArray: true }) @IsEnum(FareOption, { each: true }) fareOptions: FareOption[]; } class OriginDestinations { @ApiProperty() @IsNotEmpty() @MinLength(3) @MaxLength(3) originLocationCode: string; @ApiProperty() @IsNotEmpty() @MinLength(3) @MaxLength(3) destinationLocationCode: string; @ApiProperty() @IsDateString() @IsNotEmpty() departureDate: string; } export class OriginDestinationsDto { // 类名采用大驼峰命名,符合TS规范 @IsArray() @ApiProperty({ type: () => OriginDestinations, isArray: true }) // 指定嵌套类型和数组标识 @IsNotEmpty() @ValidateNested({ each: true }) @Type(() => OriginDestinations) originDestinations: OriginDestinations[]; @ApiProperty({ type: () => Travelers, isArray: true }) // 同上 @IsArray() @IsNotEmpty() @ValidateNested({ each: true }) @Type(() => Travelers) travelers: Travelers[]; }
关键修改说明
- Swagger Schema修复:在父DTO的数组字段上,为
@ApiProperty添加type: () => 嵌套类和isArray: true参数,明确告知Swagger数组内的对象结构。 - 增强类型安全:将枚举值定义为TS枚举类型,配合
@IsEnum校验,避免字符串拼写错误。 - 规范类命名:将
originDestinationsDto改为OriginDestinationsDto,遵循TypeScript大驼峰命名规范。 - 完善枚举校验:为
fareOptions添加@IsEnum({ each: true }),确保数组中每个元素都符合枚举规则。
额外配置检查
确保在NestJS的main.ts中启用全局验证管道并开启自动转换,否则class-transformer无法将JSON请求体转换为DTO实例:
import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes(new ValidationPipe({ transform: true, // 自动转换请求体为DTO实例 whitelist: true, // 过滤DTO中未定义的字段 })); await app.listen(3000); } bootstrap();
Postman请求示例
使用正确的嵌套结构发送请求:
{ "originDestinations": [ { "originLocationCode": "PEK", "destinationLocationCode": "SHA", "departureDate": "2024-10-01" } ], "travelers": [ { "travelerType": "ADULT", "fareOptions": ["STANDARD"] } ] }
内容的提问来源于stack exchange,提问作者jatin
相关产品推荐
相关产品推荐

