Возможно ли проверить один параметр маршрута?

#javascript #node.js #typescript #nestjs #class-validator

#javascript #node.js #typescript #nestjs #класс-валидатор

Вопрос:

Допустим, у меня есть следующий маршрут:

 companies/{companyId}/departments/{departmentId}/employees
  

Возможно ли проверить оба идентификатора ресурсов ( companyId , departmentId ) отдельно? Я пробовал следовать, но это не работает.

 class ResourceId {
  @IsNumberString()
  @StringNumberRange(...) // my custom validator
  id: number;
}

@Get(':companyId/departments/:departmentId/employees')
getEmployees(
  @Param('companyId') companyId: ResourceId,
  @Param('departmentId') departmentId: ResourceId,
) {}
  

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

Ответ №1:

Начиная с 2022 года, в документах NestJS говорится, что можно проверять параметры маршрута, используя встроенный канал проверки.

В контроллере:

 @Get(':id')
findOne(@Param() params: FindOneParams) {
  return 'This action returns a user';
}
  

Класс проверки:

 import { IsNumberString } from 'class-validator';

export class FindOneParams {
  @IsNumberString()
  id: number;
}
  

Ссылка:https://docs.nestjs.com/techniques/validation#auto-validation

Комментарии:

1. Было ли доказано, что это работает? Начиная с Nestjs 8.4.4 с глобально установленным ValidationPipe({ transform: true, whitelist: true, } параметром, который не проверяется как числовая строка

Ответ №2:

Проблема в том, что у вас здесь простая строка. Чтобы проверка с помощью class-validator сработала, вы должны создать экземпляр класса, в вашем случае ResourceId . Встроенный ValidationPipe ожидает, что значение будет {id: '123'} вместо '123' того, чтобы иметь возможность преобразовывать его автоматически. Но вы можете легко создать свой собственный канал проверки, который выполняет это дополнительное преобразование.

 export class ParamValidationPipe implements PipeTransform {
  async transform(value, metadata: ArgumentMetadata) {
    if (metadata.type === 'param') {
      // This is the relevant part: value -> { id: value }
      const valueInstance = plainToClass(metadata.metatype, { id: value });
      const validationErrors = await validate(valueInstance);
      if (validationErrors.length > 0) {
        throw new BadRequestException(validationErrors, 'Invalid route param');
      }
      return valueInstance;
    } else {
      return value;
    }
  }
}
  

Затем вы можете использовать его на своем контроллере:

 @UsePipes(ParamValidationPipe)
@Get(':companyId/departments/:departmentId/employees')
getEmployees(
  @Param('companyId') companyId: ResourceId,
  @Param('departmentId') departmentId: ResourceId,
) {
  return `id1: ${companyId.id}, id2: ${departmentId.id}`;
}
  

Комментарии:

1. Вы также можете использовать class-transformer-validator для выполнения всех шагов преобразования, валидации и проверки списка ошибок за один вызов 🙂

2. Хороший момент. 🙂 Я не собираюсь менять свой ответ, потому что добавление примечаний об установке другого пакета сделало бы его еще длиннее, но я думаю, что это очень полезный комментарий.