Nest: @Query() does not transform to DTO

Created on 11 Oct 2019  路  7Comments  路  Source: nestjs/nest

Bug Report

Current behavior

I have a controller that needs to recive data from the request query and I want to put that data into a DTO using @Query() but it does not properly transform the DTO to the target interface

Input Code

import { Get, Controller, Query, Post, Body, UsePipes, ValidationPipe } from '@nestjs/common';

interface TestDto {
  field1: number;
  field2: boolean;
}

@Controller()
export class AppController {
  constructor() {}

  @Get()
  @UsePipes(new ValidationPipe({ whitelist: false, transform: true}))
  root(@Query() dto: TestDto): TestDto {
    return dto;
  }

}

Expected behavior

If I call http://localhost:3000/?field1=10&field2=true&field3=test I get

{
"field1": "10",
"field2": "true",
"field3": "test"
}

But the expected result is:

{
"field1":  10,
"field2": true
}

Environment


Nest version: 5.7.4
Node version: 10.9.0
class-transformer: 0.2.3
class-validator: 0.10.1
tsc version: 1.8.10
Platform: Ubuntu 18.10

needs triage

Most helpful comment

Use @Type on your properties.
@Query always return string type so we have to cast to desired type.

Example

import { Type} from 'class-transformer';

export class TestDto {
  @IsNumber()
  @Type(()=>Number)
  field1: number;

  @IsBoolean()
  @Type(()=>Boolean)
  field2: boolean;
}

All 7 comments

Whitelist must be set as true in order to cut additionals.

https://docs.nestjs.com/techniques/validation#stripping-properties

You haven't used any validation decorator (which is required)

I'm sorry @kamilmysliwiec, I've added the decorators and changed from interface to class:

export class TestDto {
  @IsNumber()
  field1: number;
  @IsBoolean()
  field2: boolean;
}

But now, I get the following error message:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": [
    {
        "target": {
           "field1": "15",
           "field2": "false"
        },
       "value": "15",
       "property": "field1",
       "children": [],
      "constraints": {
      "isNumber": "field1 must be a number"
    }
},
{
    "target": {
       "field1": "15",
       "field2": "false"
    }, 
    "value": "false",
    "property": "field2",
    "children": [],
    "constraints": {
    "isBoolean": "field2 must be a boolean value"
  }
}
]
}

If I change @IsNumber to @IsNumberString and @IsBoolean to @IsBooleanString it validates, but I do not get the transformed dto

I'm sorry @kamilmysliwiec, I've added the decorators and changed from interface to class:

export class TestDto {
  @IsNumber()
  field1: number;
  @IsBoolean()
  field2: boolean;
}

But now, I get the following error message:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": [
    {
        "target": {
           "field1": "15",
           "field2": "false"
        },
       "value": "15",
       "property": "field1",
       "children": [],
      "constraints": {
      "isNumber": "field1 must be a number"
    }
},
{
    "target": {
       "field1": "15",
       "field2": "false"
    }, 
    "value": "false",
    "property": "field2",
    "children": [],
    "constraints": {
    "isBoolean": "field2 must be a boolean value"
  }
}
]
}

If I change @IsNumber to @IsNumberString and @IsBoolean to @IsBooleanString it validates, but I do not get the transformed dto

hey frieng,did you fix this problem?I am facing this problem now.

Use @Type on your properties.
@Query always return string type so we have to cast to desired type.

Example

import { Type} from 'class-transformer';

export class TestDto {
  @IsNumber()
  @Type(()=>Number)
  field1: number;

  @IsBoolean()
  @Type(()=>Boolean)
  field2: boolean;
}

The solution with @Type kinda works, but it'll return true for any string passed to the query param.
Another workaround is to use @Transform:

 @Transform(value => {
   if (value === 'true') return true;
   if (value === 'false') return false;
   return value;
 })

A different approach would be passing enableImplicitConversion to your ValidationPipe, as such:

app.useGlobalPipes(new ValidationPipe({
    transform: true,
    transformOptions: {
      enableImplicitConversion: true
    },
}));

Interface defined here:
https://github.com/nestjs/nest/blob/master/packages/common/interfaces/external/class-transform-options.interface.ts

Was this page helpful?
0 / 5 - 0 ratings

Related issues

anyx picture anyx  路  3Comments

cojack picture cojack  路  3Comments

JulianBiermann picture JulianBiermann  路  3Comments

yanshuf0 picture yanshuf0  路  3Comments

tronginc picture tronginc  路  3Comments