11

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.

3 Answers 3

6

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

Sign up to request clarification or add additional context in comments.

1 Comment

This is also documented in Nestjs's official doc.
3

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?

1 Comment

Is there a way to set it for only one property? So that if there are any issues, they would be limited to that specific property and not affect all the system.
1

The answer that works, to be clear for others, was posted by Kyung Lee in one of the comments and comes from the official NestJS documentation here

The code in particular that needs to be implemented is the ParseArrayPipe which specifies the type of object located in the DTO Array:

@Body(new ParseArrayPipe({ items: CreateUserDto }))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.