Nest: global ValidationPipe called twice if 'whitelist' option is enabled

Created on 16 Jan 2020  路  2Comments  路  Source: nestjs/nest

Bug Report

Current behavior

It seems to process request twice if I register ValidationPipe as global and activate 'whitelist' option.

What I tried is to transform boolean data of query parameter using @Transform in class-transformer with @Transform(value => value === 'true' || value === 'True') .

However, it returns always false regardless of what request value is. Therefore, I tried to figure out and now I found that @Transform( ... ) called twice so first time it returns true, and next true === 'true' returns false!

Input Code

Here is my repository to reproduce issue:
https://github.com/Atanatous/nest-issue-reproduce

// in main.ts
 app.useGlobalPipe(new ValidationPipe({ whitelist: true })

// in query.dto.ts
export class QueryDto {
  @Transform(value => {
      Logger.log(value)              // First: true, Second: true
      Logger.log(typeof value)      // First: 'string', Second: 'boolean'
      return value === 'true'
})
  bool: boolean
}

Expected behavior

@Transform in ValidationPipe should be called only once for each request.

Possible Solution

Environment


Nest version: > 6.7.2 
(my issue reproduce repo is 6.7.2, and my real project is 6.10.14. Both happens.)

For Tooling issues:
- Node version: 10.18.0 
- Platform:  Mac

Others:

needs triage

Most helpful comment

In order to validate your DTO, ValidationPipe has to transform your plain JS object to a class instance (@Transform() is evaluated). Now, since you aren't passing transform: true, the pipe is assuming you want to have a literal object. However, you passed whitelist: true which means that we cannot simply return the value passed to the pipe (because properties won't be whitelisted). Hence, the pipe has to transform it into a plain JS object - serialize it (@Transform() is evaluated once again).

To fix this, you can either:
a) Enable transform: true
b) Set the toClassOnly to true:

@Transform(value => {
   return value === 'true';
}, { toClassOnly: true })

All 2 comments

In order to validate your DTO, ValidationPipe has to transform your plain JS object to a class instance (@Transform() is evaluated). Now, since you aren't passing transform: true, the pipe is assuming you want to have a literal object. However, you passed whitelist: true which means that we cannot simply return the value passed to the pipe (because properties won't be whitelisted). Hence, the pipe has to transform it into a plain JS object - serialize it (@Transform() is evaluated once again).

To fix this, you can either:
a) Enable transform: true
b) Set the toClassOnly to true:

@Transform(value => {
   return value === 'true';
}, { toClassOnly: true })

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hypeofpipe picture hypeofpipe  路  27Comments

szkumorowski picture szkumorowski  路  62Comments

chaostheory picture chaostheory  路  34Comments

ArsalaBangash picture ArsalaBangash  路  27Comments

BrunnerLivio picture BrunnerLivio  路  44Comments