Search code examples
node.jstypescriptnestjstypeormclass-transformer

NestJS class-transformer ignoring Declorators on TypeORM-Entity


I am trying to use classToPlain on a TypeORM-Entity in a NestJS Project and class Transformer just ignores the @Exclude Declorator. Below are some snippets of my code:

user.entity

@Entity()
export class User {
  @Column()
  @Exclude()
  password!: string;
}

export const userToPlain = (user : User) => {
  return classToPlain<User>(user);
}

user.service

  createUser(userDTO : userCreateDTO, role?: RoleType[]) : Promise<User> {
    return new Promise<User>(async (resolve, reject) => 
      this.usersRepository.save(userDTO).then(res => {
        resolve(res);
      }).catch(reject);
    })
  }

users.controller

@Post("/create")
create(@Body() userDto : userCreateDTO, @Req() request: Request, @Res() res: Response) {
      this.userService.createUser(userDto, ["EDITOR"]).then(newUser => {
        res.status(201);
        res.json(userToPlain(newUser));
      })
  })
}

I've neither worked with NestJS, TypeORM, nor class-transformer before, so I really have no clue what's going on.


Solution

  • You're injecting @Res() into your route handler. Nest's docs explicitly state that if you use @Res() you are in charge of formatting and sending the response yourself. If you want Nest to handle the response for you, remove @Res() from the route handler, and use @UseInterceptors(ClassSerializationInterceptor) as described in the docs here

    Edit 8/3/21 to answer the question

    Apologies, I read the question too quickly and didn't notice that you are indeed calling res.send and the userToPlain method yourself.

    SO, TypeORM is a little weird with the save method, in that it only returns an object, not a class instance, so there's no metadata to be read in regards to the classToPlain method, and as such, it returns the object as is. You can verify this yourself by logging newUser instanceof User.

    What you can do about this is call plainToClass first, so that you get back an actual instance of the User class, that can then be properly serialized in the userToPlain method. You can put this in your useToClass method, or make it a part of the UserService#createUser