返回

Nest 自定义注解实战教程

前端

使用 Nest 和 class-validator进行参数校验是前不久刚接触到一个新东西,很有意思,而且在业务中很常用,就打算写一篇自定义注解的文章来总结一下自己的心得,文中代码基于 Nest 和 class-validator,如果还没用过小伙伴可以去官网瞅瞅,这里就不多介绍了。

前言

Nest 与 class-validator 配合得很好,它允许我们使用基于装饰器的验证,在dto层中我们可以通过它的一些内置注解完成对参数的一些常用校验。

但是,当我们在写业务代码时,肯定还会遇到一些特殊需求的校验,此时我们需要自己去扩展 class-validator 的能力,来实现我们自己的校验逻辑。下面就来讲一讲如何自定义一个注解并使用它。

一、创建自定义注解

首先,我们需要创建一个新的装饰器,它将用于验证我们的参数。这个装饰器可以放在任何地方,但通常情况下,我们将其放在一个单独的文件中。

import { registerDecorator, ValidationOptions } from "class-validator";

export function IsPositiveNumber(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: "isPositiveNumber",
      target: object.constructor,
      propertyName: propertyName,
      constraints: [],
      options: validationOptions,
      validator: {
        validate(value: any) {
          return typeof value === "number" && value > 0;
        },
        defaultMessage: "The value must be a positive number",
      },
    });
  };
}

这个装饰器接收一个可选的验证选项对象,该对象可以用于配置验证器。在上面的例子中,我们使用了 registerDecorator() 函数来注册我们的装饰器。

第一个参数是装饰器的元数据对象,它指定了装饰器的一些属性,如名称、目标类、属性名和验证器。

第二个参数是装饰器函数,它接收两个参数:要验证的对象和属性名。

在装饰器函数中,我们使用 registerDecorator() 函数来注册验证器。验证器包含以下属性:

  • 名称:验证器的名称。
  • 目标:验证器的目标类。
  • 属性名:验证器的属性名。
  • 约束:验证器的约束。
  • 选项:验证器的选项。
  • 验证器:验证器的验证器函数。

二、使用自定义注解

现在我们已经创建了自定义注解,我们可以使用它来验证我们的参数。

import { IsPositiveNumber } from "./is-positive-number.decorator";
import { Body, Controller, Post } from "@nestjs/common";

@Controller()
export class AppController {
  @Post()
  create(@Body() body: CreateDto) {
    // ...
  }
}

class CreateDto {
  @IsPositiveNumber()
  age: number;
}

在这个例子中,我们使用 @IsPositiveNumber() 装饰器来验证 age 属性。如果 age 的值不是一个正数,那么验证器将返回一个错误。

三、自定义注解的扩展

除了上面介绍的简单示例之外,我们还可以通过扩展 ValidationArguments 类来创建更复杂的自定义注解。

import { registerDecorator, ValidationArguments, ValidationOptions } from "class-validator";

export function IsPositiveNumber(validationOptions?: ValidationOptions) {
  return function (object: Object, propertyName: string) {
    registerDecorator({
      name: "isPositiveNumber",
      target: object.constructor,
      propertyName: propertyName,
      constraints: [],
      options: validationOptions,
      validator: {
        validate(value: any, args: ValidationArguments) {
          const [relatedPropertyName] = args.constraints;
          const relatedValue = args.object[relatedPropertyName];

          return typeof value === "number" && value > 0 && value < relatedValue;
        },
        defaultMessage: "The value must be a positive number and less than related property value",
      },
    });
  };
}

在这个例子中,我们使用 ValidationArguments 类来获取相关属性的值。然后,我们使用这些值来验证 age 的值。

总结

自定义注解是一种强大的工具,它允许我们对参数进行更复杂的验证。通过扩展 ValidationArguments 类,我们可以创建更灵活的自定义注解。

我希望这篇教程能帮助你了解如何使用 Nest 和 class-validator 来创建自定义注解。