#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. Хороший момент. 🙂 Я не собираюсь менять свой ответ, потому что добавление примечаний об установке другого пакета сделало бы его еще длиннее, но я думаю, что это очень полезный комментарий.