是否可以验证单个路由参数?

alw*_*loo 5 javascript node.js typescript class-validator nestjs

假设我有以下路线:

companies/{companyId}/departments/{departmentId}/employees
Run Code Online (Sandbox Code Playgroud)

是否可以分别验证两个资源 id ( 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,
) {}
Run Code Online (Sandbox Code Playgroud)

当单个路由中有多个参数时,我遇到了多种情况。我不想为每条路线创建单独的验证类。有没有办法以不同的方式处理这个问题?

aso*_*gor 11

截至 2022 年,NestJS 文档表示可以使用内置验证管道来验证路由参数。

在控制器中:

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

验证类:

import { IsNumberString } from 'class-validator';

export class FindOneParams {
  @IsNumberString()
  id: number;
}
Run Code Online (Sandbox Code Playgroud)

参考:https: //docs.nestjs.com/techniques/validation#auto-validation

  • 这是否已被证明有效?从 Nestjs 8.4.4 开始,全局安装了 `ValidationPipe({transform: true, whitelist: true, }`,参数未被验证为数字字符串 (5认同)

Kim*_*ern 4

问题是你这里有一个普通的字符串。为了使验证起作用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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以在控制器上使用它:

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