自定义验证规则

未匹配的标注

你可以使用validator.rule方法向验证器添加自定义规则。规则只能注册一次。因此,我们建议你在服务提供商或 预加载文件 中注册它们。

在本指南中,我们将它们保存在start/validator.ts文件中。你可以通过运行以下 Ace 命令来创建此文件,并将环境选择为“HTTP 服务器期间”

node ace make:prldfile validator

打开新创建的文件并将以下代码粘贴到其中。

// title: start/validator.ts
import { string } from '@ioc:Adonis/Core/Helpers'
import { validator } from '@ioc:Adonis/Core/Validator'

validator.rule('camelCase', (value, _, options) => {
  if (typeof value !== 'string') {
    return
  }

  if (value !== string.camelCase(value)) {
    options.errorReporter.report(
      options.pointer,
      'camelCase',
      'camelCase validation failed',
      options.arrayExpressionPointer
    )
  }
})
  • validator.rule方法接受规则名称作为第一个参数。
  • 第二个参数是规则实现。该函数接收验证中的字段值、规则选项和表示模式树的对象。

在上面的示例中,我们创建了一个camelCase规则来检查字段值是否与其 camelCase 版本相同。如果没有,我们将使用 errorReporter 类实例报告错误。

使用规则

在使用你的自定义规则之前,你必须通知 TypeScript 编译器。否则,它会抱怨规则不存在。

为了通知 TypeScript,我们将使用 declaration merging 并将属性添加到Rules接口。

在路径contracts/validator.ts处创建一个新文件(文件名不重要)并将以下内容粘贴到其中。

// title: contracts/validator.ts
declare module '@ioc:Adonis/Core/Validator' {
  interface Rules {
    camelCase(): Rule
  }
}

完成后,你可以从rules对象访问camelCase规则。

// highlight-start
import { rules, schema, validator } from '@ioc:Adonis/Core/Validator'
// highlight-end

await validator.validate({
  schema: schema.create({
    fileName: schema.string({}, [
      // highlight-start
      rules.camelCase()
      // highlight-end
    ]),
  }),
  data: {},
})

将选项传递给规则

规则也可以接受选项,它们将作为第二个参数提供给验证回调。

这次让我们从 TypeScript 接口开始,定义我们期望从规则使用者那里得到的选项。

// title: contracts/validator.ts
declare module '@ioc:Adonis/Core/Validator' {
  interface Rules {
    camelCase(maxLength?: number): Rule
  }
}

传递给规则函数的所有参数都可以作为规则实现的数组使用。因此,例如,你可以访问maxLength选项,如下所示。

validator.rule('camelCase', (
  value,
  // highlight-start
  [maxLength],
  // highlight-end
  options
) => {
  // Rest of the validation
  if (maxLength && value.length > maxLength) {
    options.errorReporter.report(
      options.pointer,
       // highlight-start
      'camelCase.maxLength', // 👈 注意这个
       // highlight-end
      'camelCase.maxLength validation failed',
      options.arrayExpressionPointer,
      { maxLength }
    )
  }
})

最后,如果你注意到,我们将规则名称作为camelCase.maxLength传递给错误报告器。这将允许用户为maxLength定义自定义验证消息。

messages: {
  'camelCase.maxLength': 'Only {{ options.maxLength }} characters are allowed'
}

规范化选项

很多时候,你希望规范化传递给验证规则的选项。例如:在用户未提供时使用默认的maxLength

我们建议你在编译阶段只对它们进行一次规范化,而不是规范化验证回调中的选项。

validator.rule方法接受一个回调函数作为第三个参数,并在编译阶段运行它。

validator.rule(
  'camelCase', // 规则名称
  () => {}, // 验证回调
  // highlight-start
  ([maxLength]) => {
    return {
      compiledOptions: {
        maxLength: maxLength || 10,
      },
    }
  }
  // highlight-end
)

然后将compiledOptions值作为第二个参数传递给验证回调。根据上面的示例,验证回调将接收maxLength作为对象。

validator.rule(
  'camelCase', // 规则名称
  // highlight-start
  (value, { maxLength }) => {}, // 验证回调
  // highlight-end
  ([maxLength]) => {
    return {
      compiledOptions: {
        maxLength: maxLength || 10,
      },
    }
  }
)

异步规则

要优化验证过程,你必须明确告知验证器您的验证规则本质上是异步的。只需从编译回调中返回async: true,然后您就可以在验证回调中使用async/await

validator.rule(
  'camelCase', // 规则名称
  // highlight-start
  async () => {}, // 验证回调
  // highlight-end
  () => {
    return {
      // highlight-start
      async: true,
      // highlight-end
      compiledOptions: {},
    }
  }
)

限制规则对特定数据类型起作用

在编译回调中,你可以访问应用了验证规则的字段的 schema type/subtype ,然后有条件地允许它仅用于特定类型。

以下是将camelCase规则限制为仅字符串模式类型的示例。

validator.rule(
  'camelCase', // 规则名称
  async () => {}, // 验证回调
  (options, type, subtype) => {
    if (subtype !== 'string') {
      throw new Error('"camelCase" rule can only be used with a string schema type')
    }

    return {
      compiledOptions: {},
    }
  }
)

如果有人尝试对非字符串字段使用camelCase规则,则会引发异常。

schema: schema.create({
  fileName: schema.number([
    rules.camelCase() // 会导致运行时出错
  ]),
}),

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/adonisjs/5.x/va...

译文地址:https://learnku.com/docs/adonisjs/5.x/va...

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~