Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent unwanted object properties from the client in nestjs while updating an existing row in mongodb

Creating a new user will ignore non-specified objects from create-user.dto.ts

However when I update the user it will add unwanted fields like this:

// update-user.dto.ts
import { IsEmail } from 'class-validator';
import { Address } from '../model/address';

export class UpdateUserDto {
  firstName: string;

  lastName: string;

  @IsEmail(undefined, { message: 'Not a valid e-mail' })
  email: string;

  username: string;

  password: string;

  addresses: Address[];
}

This is the update action from the user service

// user.service.ts
  async update(data: UpdateUserDto) {
    try {
      this.logger.log(data);
      const id = '5c6dd9852d4f441638c2df86';
      const user = await this.userRepository.update(id, data);

      return { message: 'Updated your information' };
    } catch (error) {
      this.logger.log(error);
      throw new HttpException('', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

And here is the user.controller.ts

  @Patch()
  @UsePipes(CustomValidationPipe)
  async update(@Body() data: UpdateUserDto) {
    return this.userService.update(data);
  }

The client patch data:

// Unwanted junk from client
{
  "email": "[email protected]",
  "junk": "junk"
}

The email will update properly but the row will have a new unwanted property junk with the value junk

like image 227
Tea Zulo Avatar asked Feb 21 '19 17:02

Tea Zulo


2 Answers

I'm assuming you are using class-transformer's validate method in your CustomValidationPipe.

When you pass the whitelist option to it, validate will strip away all unknown (-> no annotation in your DTO class) properties:

validate(userUpdate, { whitelist: true })

If you want to throw a validation error instead of just stripping away unknown properties, you can additionally pass the forbidNonWhitelisted option.

validate(userUpdate, { whitelist: true, forbidNonWhitelisted: true });

In the case of an update, you probably also want to use skipMissingProperties: true, so that validate will not throw an error, when e.g. lastName is not part of the update.


Note, that you should annotate all properties in your dto class, for the validation to work properly:

@IsString()
lastName: string;

@ValidateNested()
@Type(() => Address)
address: Address
like image 60
Kim Kern Avatar answered Nov 09 '22 23:11

Kim Kern


Not sure when this behavior/option was added to NestJS (perhaps it was added after the original question and accepted answer), but the best way to achieve unknown property stripping would be that:

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

That is it. By just making sure you have whitelist: true in your config, you won't be getting any unknown/invalid property.

You can also completely stop the request by setting another property called forbidNonWhitelisted to true.

More on that here: https://docs.nestjs.com/techniques/validation#stripping-properties

like image 14
Bruno Krebs Avatar answered Nov 10 '22 00:11

Bruno Krebs