Nest: Parse controller method argument into Entity

Created on 22 Oct 2017  路  16Comments  路  Source: nestjs/nest

Hello!
I think a much needed feature is to automatically parse Controller method arguments into the appropriate Entity. This is very easy to do using a pipe, but I think it is worth making its own example, or even an npm package, so that it can be plugged in effortlessly.

import { HttpException } from '@nestjs/core';
import { PipeTransform, Pipe, ArgumentMetadata, HttpStatus } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';

@Pipe()
export default class EntityParserPipe implements PipeTransform<any> {
    async transform(value, metadata: ArgumentMetadata) {
      const { metatype } = metadata;
      if (!metatype || !this.toValidate(metatype)) {
          return value;
      }
      const entity = plainToClass(metatype, value);
      const errors = await validate(entity);
      if (errors.length > 0) {
          throw new HttpException('Validation failed', HttpStatus.BAD_REQUEST);
      }
      return entity;
    }

    private toValidate(metatype): boolean {
      const types = [String, Boolean, Number, Array, Object];
      return !types.find((type) => metatype === type);
    }
}

This is what I'm using, and you'll notice its almost exactly the same as the validation example from the pipe tutorial. Therefore, I don't want to post this on npm and claim credit. Could I commit it to the core repo? Again, I know this is an easy feature to implement by hand, but I think it should be available out of the box because it is so handy, and expected.

discussion 馃敟 type

Most helpful comment

Hi @adammfrank,
This pipe depends on the two 3rd party packages. That's the reason why I don't think it's a good idea to make it a part of the core package, but I'm wondering about the new @nestjs/utils package. It might contain useful interceptors / guards as well as pipes (for example ParseXPipe / ValidationPipe) 馃檪

All 16 comments

Hi @adammfrank,
This pipe depends on the two 3rd party packages. That's the reason why I don't think it's a good idea to make it a part of the core package, but I'm wondering about the new @nestjs/utils package. It might contain useful interceptors / guards as well as pipes (for example ParseXPipe / ValidationPipe) 馃檪

Is utils in progress, or just and idea? I'd be happy to submit a PR to start it.

@adammfrank the idea only

Do you mean in a new repo, called "utils" under the nestjs organization? If so, would you be able to add me to the organization so that I can start it? Or would you be able to start the repo so that I can submit a PR with this feature?

Hi @adammfrank,
I have created an empty repository under github org now https://github.com/nestjs/utils so everyone can submit any PR here 馃檪

Dependencies aren鈥檛 a problem imo; it鈥檚 server-side so bundle size doesn鈥檛 matter. Adding another package add another layer of complexity

I can also take a look at reimplementing the needed dependencies. Might not be too hard. Haven't tried though.

@wbhob Hmm.. I agree that another package may increase complexity. Maybe instead of creating the new package, we could make use of the common package? Then put these 2 libraries as deep dependencies.

@kamilmysliwiec In terms of architecting Nest (I think I emailed you about this, or openned some other issue): everything that one simple REST app needs to run should be contained in Core, and it should not depend on any other Nest package. Right now, Core depends on every other package (#212 fixes this, to some degree), and this is an antipattern. Everything else should be in an external package.

So the pertinence here is to put additional basic functionality, like this pipe, in Core.

@kamilmysliwiec PR coming soon

@adammfrank I have merged your pull request today. Thanks!! 馃帀

@adammfrank @kamilmysliwiec I'm a bit confused about what happened here. The original discussion and pull request was for a pipe that created an entity, but the last comment on the pull request says it was renamed to ValidationPipe. ValidationPipe, however, does what its name suggests, but doesn't return the entity.

Am I missing something?

The original PR was return object;, but ValidationPipe is implemented as return value;.
I think it has to be separated to ValidationPipe returns value, and ModelParserPipe returns object.
@FreakTheMighty @kamilmysliwiec

ModelParserPipe is useful in this case:

import { IsInt, IsNumberString, IsPositive, Min } from 'class-validator';
import { Type } from 'class-transformer';

export class PhotoQuery {
  @Type(() => Number)
  @IsInt()
  @Min(0)
  readonly skip: number;

  @Type(() => Number)
  @IsInt()
  @IsPositive()
  readonly take: number;
}

Query is always parsed as string, so it is hard to validate with class-validator package. And you can validate and sanitize model with just one class definition.

I got params from a controller method automatically parsed into an entity object using the nestjs extensions here:

https://github.com/chanlito/nestjs-extensions/issues/5

It's sweet!

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

janckerchen picture janckerchen  路  3Comments

menme95 picture menme95  路  3Comments

artaommahe picture artaommahe  路  3Comments

hackboy picture hackboy  路  3Comments

anyx picture anyx  路  3Comments