RustyJoe
RustyJoe

Reputation: 75

NestJS ValidationPipe is not working properly for @Query()

I'm trying to transform some query params from string to int using the in-build NestJS ValidationPipe, but it doesn't seem to be working correctly,

Here is my controller :

import {
..., ValidationPipe
} from '@nestjs/common';

...

@UseGuards(JwtAuthGuard)
@Get()
findAll(@Req() req, @Query(new ValidationPipe({
    transform: true,
    transformOptions: { enableImplicitConversion: true },
    forbidNonWhitelisted: true,
})) query: GetTestDto) {
    return this.testService.findAll(query, req.user.id);
}

Here is my DTO :

import { IsInt, IsOptional, IsString } from 'class-validator';
import { Transform } from 'class-transformer';

export class GetTestDto {
    @IsOptional()
    @IsString()
    public search: string;

    @IsOptional()
    @Transform(({value}) => {
        console.log(typeof value); // => string / I'm just testing here
        return value
    })
    @IsInt()
    public page: number;

    @IsOptional()
    @IsInt()
    public limit: number;
}

main.ts :

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import cookieParser from 'cookie-parser';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.setGlobalPrefix('api');
    app.use(cookieParser());
    app.useGlobalPipes(new ValidationPipe());
    await app.listen(3000);
}

bootstrap();

when I try to call GET http://127.0.0.1:3000/api/test?page=1&limit=10 I get this

validation error from the DTO I think:
{
    "statusCode": 400,
    "message": [
        "page must be an integer number",
        "limit must be an integer number"
    ],
    "error": "Bad Request"
} 

I've tried deleting node_modules and dist folders, but nothing changed. I don't want to use @Transform() in the DTO as a solution, I would prefer for the pipe to do the changing with the enableImplicitConversion: true

Can I please get some help?

Thank you

Upvotes: 4

Views: 4995

Answers (2)

Baraka Marawi
Baraka Marawi

Reputation: 106

  1. Pass the ValidationPipe options in the main.ts file
app.useGlobalPipes(
    new ValidationPipe({
      transform: true,
      transformOptions: {
        enableImplicitConversion: true,
      },
      whitelist: true,
    })
  );
  1. Get rid of the @Transform decorator in your dto class.

  2. Get rid of the ValidationPipe passed to the @Query decorator in your controller

@UseGuards(JwtAuthGuard)
@Get()
findAll(@Req() req, @Query() query: GetTestDto) {
    return this.testService.findAll(query, req.user.id);
}

Upvotes: 9

Jay McDoniel
Jay McDoniel

Reputation: 70600

Query (@Query()) and URL (@Param()) parameters always come in as strings. To force them to resolve to numbers you can add @Type(() => Number) so that class-transformer turns them into a number and class-validator then reads the correct value

Upvotes: -1

Related Questions