# 使用

## 概念

#### 验证链

每个 `acr.string()` 或者 `acr.number()` 这样的类型声明后面返回的都是一个 `chain`我们称之为 **验证链** 。它就像一个链条，声明了我们对这个字段的数据要进行的种种验证。而数据会在这个链条上依次验证，直到全部通过或者某个验证没有通过为止（前面的验证没有通过，后面的验证不会继续执行）。

```javascript
await acr.string().min(2).max(5).equal('bar').validate('foobar');
```

在上面的例子中，验证链上分别有 3 个规则（`min`, `max`, `equal`），当到达第二个(`max`)时，`foobar` 字符数大于了 5，因此失败，而 `equal` 验证则不会执行。

## 数据验证

```javascript
await acr.validate({
    foo: 'bar'
}, {
    foo: acr.string().min(2).max(5).equal('bar')
});
```

数据验证方法接受两个参数：

`data`: 用于验证的数据

`rules`: 验证规则

比如在 egg 中（推荐在 egg 中使用 [egg-acr](https://github.com/seekcx/egg-acr) 插件），我们可以将 ctx 上的表单数据进行验证：

```javascript
await acr.validate(ctx.request.body, {
    // rules
});
```

## 默认值

一些可选的参数常常拥有一个默认值，虽然实现并不复杂，但这无疑增加了代码的复杂程度，也不够优雅，因此，从 1.2.0 开始 acr 支持设置默认值。

```javascript
const [ foo ] = await acr.validate({}, {
  foo: acr.string().default('bar'),
});

foo; // 'bar';
```

有时候，可能需要复杂的计算才能得出默认值：

```javascript
const [ foo ] = await acr.validate({
  bax: 123,
}, {
  foo: acr.string().default((data, context) => {
    return data['bax'] === 123 ? 'bar' : 456;
  }),
});

foo; // 'bar';
```

## 数据转换

很多情况下，我们验证的数据就是即将使用的数据。为此，acr 提供了一个便捷的方式来获取数据和转换数据。

```javascript
const { nickname, password } = await acr.validate({
    nickname: 'seek',
    password: 'secret'
}, {
    nickname: acr.string().max(12).transform(value => value + 'cx')
    password: acr.string({ 
            transform: value => value + 'salt'
        })
        .max(32);
});

console.log(nickname); // seekcx 
console.log(password); // secretsalt
```

转换函数的参数是一个 `(value: any): Promise<any>` 类型的闭包，闭包会得到一个 `value`，返回值会被作为最终数据。

上面的例子展示了两种对数据进行转换的方式：

第一种是在验证链上使用 `transform` ，第二种是在声明时使用配置的方式。除此之外，还可以在 配置 中声明 chians 来声明默认的转换，详细可以参考 [配置](/acr/config.md)。

## 参数命名

有时候的验证的错误提示在某些场景显得不那么友好。比如：

```javascript
await acr.validate({
    nickname: 'foobar',
}, {
    nickname: acr.string().max(5),
});
```

这种情况，大多数验证组件都会提示：`nickname must be at most 5 characters` 。这看起来似乎没有什么不对。但当我们把语言环境切换到 中文 时，这个错误会变为 `nickname不能超过 5 个字符`。这对用户来说十分奇怪，因为用户并不知道这个 `nickname` 什么意思。

为了解决这个问题，acr 支持给参数命名。

```javascript
await acr.validate({
    nickname: 'foobar',
}, {
    nickname: acr.string('昵称').max(5),
});
```

这样，`nickname不能超过 5 个字符`就会变成 `昵称不能超过 5 个字符`。

可能你会觉得，这样写的话，在英文条件下，不就变成了 `昵称 must be at most 5 characters` 吗？也并不友好啊。我们考虑过这种情况，认为这个不应该是 acr 处理的范围，acr 只负责提供这么一个功能，不能负责翻译其中的内容。因此，你可以在你的应用中使用国际化的方法自行转换。比如在 egg 中：

```javascript
await acr.validate({
    nickname: 'foobar',
}, {
    nickname: acr.string(ctx.__('nickname')).max(5),
});
```

和数据转换一样，参数命名也支持配置的方式。参考 [配置](/acr/config.md)

## 错误模板

为了错误提示更加友好，基于 lodash 的 template，实现了一套简单的模板引擎。

```javascript
"{ name || path } required"
```

模板中，变量以大括号 `{}` 作为分割，大括号里面的区域可以是任何 js 代码。

我们内置了一些与此验证相关的变量，可以直接在模板中使用：

* `name` 参数名称，上文 参数命名 章节所设置的名称
* `path` 参数路径，实际上是参数在数据中的 key，命名为 path 是为后续打算实现的嵌套深度验证功能做准备
* `params` 此次验证传递的所有参数


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://seek.gitbook.io/acr/shi-yong.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
