6

I am trying to validate an array of objects using DTO in nestjs. I have tried it but the data is not getting validated. I tried to search a lot but didn't get any answer. These are my files:

trivia.controller.ts file

import { Controller, Post, Body, ParseArrayPipe } from '@nestjs/common';
import { LoggerService } from '../logger/logger.service';
import { TriviaService } from './trivia.service';
import { PostTriviaScoreDto } from './dto/post-trivia-score.dto';

@Controller('trivia')
export class TriviaController {
  constructor(private readonly logger: LoggerService, private readonly triviaService: TriviaService) {}

    @Post('score')
    postTriviaScore(@Body(new ParseArrayPipe({ items: PostTriviaScoreDto })) postTriviaScoreDto: PostTriviaScoreDto) {
        this.logger.info('Trivia Controller : postTriviaScore : start');
        return this.triviaService.postTriviaScore(postTriviaScoreParamsDto, postTriviaScoreDto);
    }
}

trivia.service.ts file

import { LoggerService } from '../logger/logger.service';
import { PostTriviaScoreDto } from './dto/post-trivia-score.dto';

 @Injectable()
export class TriviaService {
  constructor(
    private readonly logger: LoggerService,
  ) {}
    postTriviaScore(allPlayersTriviaScore: PostTriviaScoreDto) {
            this.logger.info('Trivia Service : postTriviaScore : start');
            console.log('allPlayersScore ', allPlayersTriviaScore);
    
    }
}

post-trivia-score.dto.ts file

import { Type } from 'class-transformer';
import { IsNotEmpty, IsUUID, ValidateNested } from 'class-validator';

class TriviaScore {
  @IsNotEmpty()
  @IsUUID()
  question_id: string;

  @IsNotEmpty()
  @IsUUID()
  selected_option_id: string;

  @IsNotEmpty()
  answered_in_time: number;
}

export class PostTriviaScoreDto {
  @ValidateNested({ each: true })
  @Type(() => TriviaScore)
  items: TriviaScore[];
}

Structure of my JSON

[
  {
    "question_id": "088f1344-061e-4bcc-966f-512775f1f082",
    "selected_option_id": "72305e08-fedd-49b1-adb9-1dd92c88f4db",
    "answered_in_time": 2
  }
]

The properties are not getting validated here. Even if I pass a string in answered_in_time field, it accepts the body and doesn't throw an error or if I pass empty string in any of the fields then also it accepts the request body.

Please help me if you guys know the solution as I am really stuck here.

Wasim
  • 73
  • 1
  • 2
  • 7

2 Answers2

2

I think the nested class there is not initialised and use it for type reference only so class-transformer does not know how to convert it to class instance.

set enableImplicitConversion: true can request class-transformer to convert it implicitly

main.ts

import { ValidationPipe } from '@nestjs/common';
app.useGlobalPipes(
    new ValidationPipe({
      transformOptions: {
        enableImplicitConversion: true, // allow conversion underneath
      },
    }),
);

After that, the nested properties should be able to be validated.


Some said implicit conversion may have problem on other cases but I cannot find a clean solution if class is not instantiated:

Why should we NOT use enableImplicitConversion when using class-transformer?

Mic Fung
  • 5,404
  • 2
  • 7
  • 17
1

I have also faced such problem and after googling I have fount that using

new ParseArrayPipe({items: YourDto, whitelist: true})

in controller. You also did this, you said body would be array but your dto is not array actually

postTriviaScoreDto: PostTriviaScoreDto // --> mistake

If you did:

postTriviaScoreDto: PostTriviaScoreDto[] // this will solve your problem
 

Information is taken from this website

Eugene09
  • 43
  • 6