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
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;
}
}
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
}
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
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.
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
Most helpful comment
Use
@Type
on your properties.@Query
always return string type so we have to cast to desired type.Example