nest: @Body() don't transfer body object to dto object

I’m submitting a…


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

@Controller()
export class ApiController {
  @Post()
  async index(@Body() body: BodyDTO) {
     // `body` is not a BodyDTO, just a normal object
     console.log(body instanceof BodyDTO) // false
  }
}

Expected behavior

@Controller()
export class ApiController {
  @Post()
  async index(@Body() body: BodyDTO) {
     console.log(body instanceof BodyDTO) // true
  }
}

What is the motivation / use case for changing the behavior?

Sometimes, I need to do something with dto object.

class BodyDTO {
  readonly firstName: string
  readonly lastName: string
  get name(): string { return this.firstName + ' ' + this.lastName }
}

It’s not convenience without dto object. And it’s not a intuitive way.

Environment


Nest version: 4.6.6

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

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 17 (2 by maintainers)

Most upvoted comments

@unlight Thanks

It works for me.

// ...
async index(@Body(new ValidationPipe({transform: true})) body: BodyDTO) {
  console.log(body instanceof BodyDTO) // true
}
// ...

I suggest updating docs.

Transforming plain object to specific class is not applying automatically. You need to use pipes (see docs) You can write your own, or you can use built-in pipe ValidationPipe.

I’m having an issue with Postman where if I send a POST via the command line, for example:

curl -d ‘{“phone”:“value1”}’ -H “Content-Type: application/json” -X POST http://localhost:3000/auth/requestCode

It works!

But if I send it through Postman, the @Body() is an empty object. Has anyone seen this?

I was able to get postman to accept body. In body tab select raw option. Then to the right of that I selected application/json in the dropdown. Entered my object into the text area and it converted it correctly using @Body myVar: MyType

{
    "toAddress": "whoyouare@gmail.com",
    "message": "hello",
    "useSecureEmail": true,
    "contactPhoneNumber": "509931212"
}

@unlight Thanks

It works for me.

// ...
async index(@Body(new ValidationPipe({transform: true})) body: BodyDTO) {
  console.log(body instanceof BodyDTO) // true
}
// ...

I suggest updating docs.

@XGHeaven It’s also useful to see the other options the @ValidationPipe() supports. The one I found very useful for security purposes is the whitelist. Here is a use case:

User.create(body).save()

The problem with this is that it’s possible to inject into the body of the request properties that are not listed in the DTO, for example, isAdmin: true or whatever flag/role you use to identify admin users.

Ideally, we should strip out from the body non-allowed properties. whitelist: true does just that.

I’m having an issue with Postman where if I send a POST via the command line, for example: curl -d ‘{“phone”:“value1”}’ -H “Content-Type: application/json” -X POST http://localhost:3000/auth/requestCode It works! But if I send it through Postman, the @Body() is an empty object. Has anyone seen this?

I was able to get postman to accept body. In body tab select raw option. Then to the right of that I selected application/json in the dropdown. Entered my object into the text area and it converted it correctly using @Body myVar: MyType

{
    "toAddress": "whoyouare@gmail.com",
    "message": "hello",
    "useSecureEmail": true,
    "contactPhoneNumber": "509931212"
}

Hei, thank you! THANK YOU!

It’s also useful to see the other options the @ValidationPipe() supports. The one I found very useful for security purposes is the whitelist.

I second that. It’s also possible to forbid processing requests that have unexpected properties using the forbidNonWhitelisted option.

@XGHeaven The docs (https://docs.nestjs.com/techniques/validation#stripping-properties) also mention now that payloads are not automatically transformed to DTOs but it also took me a whole to find it so it was good that you brought it up!

Instead of using new ValidationPipe({transform: true})) on every @Body you can also enable transformation on a global application level:

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

I’m having an issue with Postman where if I send a POST via the command line, for example:

curl -d ‘{“phone”:“value1”}’ -H “Content-Type: application/json” -X POST http://localhost:3000/auth/requestCode

It works!

But if I send it through Postman, the @Body() is an empty object. Has anyone seen this?

The new documentation provides more details about built-in ValidationPipe. https://docs.nestjs.com/v5

I’ll merge docs soon.