NestJS中POST请求DTO验证正常,PUT请求验证失效求助
NestJS Validation 异常:PUT请求未触发枚举数组验证
我在使用NestJS的Validation时遇到问题:需要验证一个对象数组类型的属性,其中对象包含枚举数组类型的字段。POST请求下验证正常——传入枚举外的无效字符串会抛出错误,但使用相同校验规则的PUT请求中,包含枚举数组capabilities的defaultCapabilities字段却不触发验证。邮箱等其他字段的验证在两种请求中都正常工作。
附上相关代码,若需更多信息请告知。
创建DTO(TenantCreateDto)
import { ApiProperty } from '@nestjs/swagger'; import { UserRole, UserCapability, CapabilitiesMap } from '../schemas/supp-tenant.schema'; import { IsEmail, ValidateNested, IsArray } from '@nestjs/class-validator'; import { Type } from '@nestjs/class-transformer'; export class TenantCreateDto { @ApiProperty({ example: 'client1', description: '租户名称' }) client: string; @IsEmail() @ApiProperty({ example: 'client1@gmail.com', description: '租户邮箱' }) email: string; @IsArray() @Type(() => CapabilitiesMap) @ValidateNested({ each: true }) @ApiProperty({ example: [{ role: UserRole.USER, capabilities: [UserCapability.CanCreatePost] }], type: [CapabilitiesMap], description: '租户默认权限配置' }) defaultCapabilities: CapabilitiesMap[]; }
更新DTO(TenantUpdateDto)
import { ApiProperty } from '@nestjs/swagger'; import { UserRole, UserCapability, CapabilitiesMap } from '../schemas/supp-tenant.schema'; import { IsEmail, ValidateNested, IsArray } from '@nestjs/class-validator'; import { Type } from '@nestjs/class-transformer'; export class TenantUpdateDto { @ApiProperty({ example: 'client1', description: '租户名称' }) client: string; @IsEmail() @ApiProperty({ example: 'client1@gmail.com', description: '租户邮箱' }) email: string; @IsArray() @Type(() => CapabilitiesMap) @ValidateNested({ each: true }) @ApiProperty({ example: [{ role: UserRole.USER, capabilities: [UserCapability.CanCreatePost] }], type: [CapabilitiesMap], description: '租户默认权限配置' }) defaultCapabilities: CapabilitiesMap[]; }
控制器(TenantsController)
import { Body, Controller, Delete, Get, Param, Post, Put } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { TenantsService } from '../services/tenants.service'; import { TenantCreateDto } from '../dtos/tenant-create.dto'; import { TenantUpdateDto } from '../dtos/tenant-update.dto'; import { TenantResponseDto } from '../dtos/tenant-response.dto'; @ApiTags('Tenants') @Controller('tenants') export class TenantsController { constructor(private readonly tenantsService: TenantsService) { } @Post() @ApiOperation({ summary: '创建新租户' }) @ApiResponse({ status: 201, description: '租户创建成功', type: TenantResponseDto }) async create(@Body() createTenantDto: TenantCreateDto): Promise<TenantResponseDto> { return this.tenantsService.create(createTenantDto); } @Get() @ApiOperation({ summary: '获取所有租户' }) @ApiResponse({ status: 200, description: '租户列表', type: [TenantResponseDto] }) async findAll(): Promise<TenantResponseDto[]> { return this.tenantsService.findAll(); } @Get(':id') @ApiOperation({ summary: '根据ID查询租户' }) @ApiResponse({ status: 200, description: '匹配ID的租户信息', type: TenantResponseDto }) async findOne(@Param('id') id: string): Promise<TenantResponseDto> { return this.tenantsService.findOne(id); } @Put(':id') @ApiOperation({ summary: '根据ID更新租户' }) @ApiResponse({ status: 200, description: '租户更新成功', type: TenantResponseDto }) async update(@Param('id') id: string, @Body() updateTenantDto: TenantUpdateDto): Promise<TenantResponseDto> { return this.tenantsService.update(id, updateTenantDto); } @Delete(':id') @ApiOperation({ summary: '根据ID删除租户' }) @ApiResponse({ status: 200, description: '租户删除成功', type: TenantResponseDto }) async remove(@Param('id') id: string): Promise<TenantResponseDto> { return this.tenantsService.remove(id); } }
服务(TenantsService)
import { Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { SuppTenant, SuppTenantDocument } from '../schemas/supp-tenant.schema'; import { TenantCreateDto } from '../dtos/tenant-create.dto'; import { TenantUpdateDto } from '../dtos/tenant-update.dto'; import { TenantResponseDto } from '../dtos/tenant-response.dto'; @Injectable() export class TenantsService { constructor(@InjectModel(SuppTenant.name) private tenantModel: Model<SuppTenantDocument>) { } async create(createTenantDto: TenantCreateDto): Promise<TenantResponseDto> { const createdTenant = new this.tenantModel(createTenantDto); const savedTenant = await createdTenant.save(); return new TenantResponseDto(savedTenant); } async findAll(): Promise<TenantResponseDto[]> { const tenants = await this.tenantModel.find().exec(); return tenants.map(tenant => new TenantResponseDto(tenant)); } async findOne(id: string): Promise<TenantResponseDto> { const tenant = await this.tenantModel.findById(id).exec(); if (!tenant) { return null; } return new TenantResponseDto(tenant); } async update(id: string, updateTenantDto: TenantUpdateDto): Promise<TenantResponseDto> { const updatedTenant = await this.tenantModel.findByIdAndUpdate(id, updateTenantDto, { new: true }).exec(); if (!updatedTenant) { return null; } return new TenantResponseDto(updatedTenant); } async remove(id: string): Promise<TenantResponseDto> { const removedTenant = await this.tenantModel.findByIdAndRemove(id).exec(); if (!removedTenant) { return null; } return new TenantResponseDto(removedTenant); } }
Mongo Schema(SuppTenantSchema)
我尝试在Mongo Schema中添加验证但无效:
import { IsArray, IsEnum } from '@nestjs/class-validator'; import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { ApiProperty } from '@nestjs/swagger'; import { HydratedDocument } from 'mongoose'; export type SuppTenantDocument = HydratedDocument<SuppTenant>; export enum UserCapability { CanCreatePost = 'canCreatePost', CanCreateComment = 'canCreateComment', CanSupport = 'canSupport', CanCreateReport = 'canCreateReport', CanCreateProject = 'canCreateProject', } export enum UserRole { ADMIN = 'admin', MODERATOR = 'moderator', EDITOR = 'editor', USER = 'user', } @Schema({ _id: false, versionKey: false }) export class CapabilitiesMap { @ApiProperty({ enum: UserRole, default: UserRole.USER, example: UserRole.USER, description: '用户角色' }) @Prop({ type: String, enum: UserRole }) @IsEnum(UserRole) role: UserRole; @ApiProperty({ enum: UserCapability, isArray: true, default: [], uniqueItems: true, description: '用户权限', example: [UserCapability.CanCreatePost] }) @IsArray() @IsEnum(UserCapability, { each: true }) @Prop({ type: [String], enum: UserCapability, default: [] }) capabilities: UserCapability[]; } const CapabilitiesMapSchema = SchemaFactory.createForClass(CapabilitiesMap); @Schema() export class SuppTenant { @Prop() client: string; @Prop({ required: true, minlength: 4, maxlength: 32, match: /.+@.+\..+/ }) email: string; @Prop() creationDate: string; @Prop({ type: [CapabilitiesMapSchema], default: [] }) defaultCapabilities: CapabilitiesMap[]; } export const SuppTenantSchema = SchemaFactory.createForClass(SuppTenant);
期望行为:PUT请求中传入capabilities无效字符串时,能像POST请求一样触发验证错误,但目前PUT请求会直接接受无效值。
内容的提问来源于stack exchange,提问作者SteDeus
相关产品推荐
相关产品推荐

