Como validar array de objetos em DTO quando o endpoint usa multipart/form-data no NestJS?
10:33 13 Nov 2025

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?

nestjs nestjs-swagger