Как предотвратить нежелательные свойства объекта от клиента в nestjs при обновлении существующей строки в mongodb

Создание нового пользователя будет игнорировать не указанные объекты из create-user.dto.ts

Однако, когда я обновляю пользователя, он добавляет нежелательные поля, как это:

// 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[];
}

Это действие по обновлению от пользовательского сервиса

// 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);
    }
  }

А вот и файл user.controller.ts

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

Данные патча клиента:

// Unwanted junk from client
{
  "email": "newemail@gmail.com",
  "junk": "junk"
}

email будет обновляться правильно, но строка будет иметь новое нежелательное свойство junk со значением junk

5 ответов

Я предполагаю, что вы используете class-transformer"s validate метод в вашем CustomValidationPipe,

Когда вы передаете whitelist вариант к нему, validate удалит все неизвестные (-> нет аннотации в вашем классе DTO) свойства:

validate(userUpdate, { whitelist: true })

Если вы хотите выбросить ошибку проверки вместо того, чтобы просто удалить неизвестные свойства, вы можете дополнительно передать forbidNonWhitelisted вариант.

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

В случае обновления, вы, вероятно, также хотите использовать skipMissingProperties: true, так что validate не выдаст ошибку, когда, например, lastName не является частью обновления.


Обратите внимание, что вы должны аннотировать все свойства в вашем классе dto, чтобы проверка работала правильно:

@IsString()
lastName: string;

@ValidateNested()
@Type(() => Address)
address: Address

Не уверен, когда это поведение/опция было добавлено в NestJS (возможно, оно было добавлено после исходного вопроса и принятого ответа), но лучший способ добиться удаления неизвестного свойства:

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

Вот и все. Просто убедитесь, что у вас есть whitelist: trueв вашей конфигурации вы не получите неизвестного/недопустимого свойства.

Вы также можете полностью остановить запрос, установив другое свойство с именем forbidNonWhitelistedк true.

Подробнее об этом здесь: https://docs.nestjs.com/techniques/validation#stripping-properties

Для таких новичков, как я, которые все еще задаются вопросом, вот простой способ реализовать это:

      @UsePipes(new ValidationPipe({ whitelist: true }))

Поместите декоратор под декоратор методов (@Post, @Put и т. д.)

ОбаUsePipeиValidationPipeимпортируются@nestjs/common

Если вы также хотите выдать ошибку для неожиданных свойств, ее можно настроить следующим образом:

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

Неожиданное свойство приведет к

      {
 "statusCode": 400,
 "message": [
    "property XXX should not exist"
 ],
 "error": "Bad Request"
}

Обсуждение можно найти здесь

Я нашел решение:

Вот как должен выглядеть user.service.ts update():

const user = await this.userRepository.create(data);

должен быть добавлен до

await this.userRepository.update(id, user);

Вот полное обновление user.service.ts ()

  async update(data: UpdateUserDto) {
    this.logger.log(data);

    // added for testing purposes (id should be based on active user)
    const id = '5c6ef2c823bf4e3414d65cd0';
    const user = await this.userRepository.create(data);
    await this.userRepository.update(id, user);

    return { message: 'Updated your information' };
  }

Теперь любые нежелательные свойства не будут добавлены в строку

Другие вопросы по тегам