Estou com dificuldade para validar objetos aninhados em um DTO quando o endpoint usa multipart/form-data no NestJS.
Tenho um endpoint que cadastra um governador, e preciso enviar tanto os dados básicos quanto uma lista de mandatos (CreateMandatoDto[]).
O problema é que, por usar multipart/form-data, o campo mandatos chega como uma string, e o @ValidateNested() não está funcionando.
Controller
@Post()
@UseInterceptors(FileInterceptor('imagemPerfil', perfilUploadOptions))
@ApiConsumes('multipart/form-data')
async create(
@Body() createGovernadorDto: CreateGovernadorDto,
@UploadedFile() file: Express.Multer.File,
) {
return await this.governadorService.create(createGovernadorDto, file);
}
CreateGovernadorDto
import { ApiProperty } from '@nestjs/swagger';
import { Expose, Transform, Type } from 'class-transformer';
import { IsArray, IsOptional, ValidateNested } from 'class-validator';
import { CreateMandatoDto } from './create-mandato.dto';
export class CreateGovernadorDto {
@ApiProperty({ example: 'Ricardo' })
nome: string;
@ApiProperty({ example: 'Coutinho' })
sobrenome: string;
@ApiProperty({ example: 'Ricardo Coutinho é um político brasileiro...' })
resumoBio: string;
@ApiProperty({
description: 'Arquivo da imagem de perfil',
type: 'string',
format: 'binary',
})
imagemPerfil: string;
@ApiProperty({
description: 'Lista de mandatos do governador',
example:
'[{"dataInicio":"01-01-2011","dataFim":"31-12-2014","status":"ATIVO","siglaDoPartido":"PT"}]',
type: 'string',
required: false,
})
@Transform(({ value }) => {
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch {
return value;
}
}
return value;
})
@IsArray({ message: 'Mandatos deve ser um array.' })
@Type(() => CreateMandatoDto)
@ValidateNested({ each: true })
@IsOptional()
@Expose()
mandatos?: CreateMandatoDto[];
}
CreateMandatoDto
import { ApiProperty } from '@nestjs/swagger';
import { Expose, Transform } from 'class-transformer';
import { IsDate, IsEnum, IsNotEmpty, IsString, MaxDate } from 'class-validator';
import { formatDate } from '@/common/utils/formatDate';
import { StatusMandato } from '../entities/mandato.entity';
export class CreateMandatoDto {
@ApiProperty({ example: '01-01-2011' })
@Transform(({ value }) => formatDate(value))
@IsDate()
@MaxDate(new Date())
@IsNotEmpty()
@Expose()
dataInicio: Date;
@ApiProperty({ example: '31-12-2014' })
@Transform(({ value }) => formatDate(value))
@IsDate()
@MaxDate(new Date())
@IsNotEmpty()
@Expose()
dataFim: Date;
@ApiProperty({ enum: StatusMandato })
@IsEnum(StatusMandato)
@IsNotEmpty()
@Expose()
status: StatusMandato;
@ApiProperty({ example: 'PT' })
@IsString()
@IsNotEmpty()
@Expose()
siglaDoPartido: string;
}
Requisição (exemplo via cURL)
curl -X 'POST' \
'http://localhost:8000/governador' \
-H 'accept: */*' \
-H 'Content-Type: multipart/form-data' \
-F 'nome=Ricardo' \
-F 'sobrenome=Coutinho' \
-F 'resumoBio=Ricardo Coutinho é um político brasileiro...' \
-F 'imagemPerfil=@s.png;type=image/png' \
-F 'dataNascimento=15-05-1960' \
-F 'dataFalecimento=20-10-2020' \
-F 'mandatos=[{"dataInicio":"01-01-2011","dataFim":"31-12-2014","status":"ATIVO","siglaDoPartido":"PT"}]'
Problema
O campo mandatos chega como uma string no backend (não como array de objetos).
Mesmo usando @Transform e @ValidateNested, a validação dos campos dentro de CreateMandatoDto não ocorre.
Como posso fazer com que o NestJS parseie corretamente o JSON enviado dentro do multipart/form-data e valide o array de CreateMandatoDto?