验证
AdonisJS 中的数据验证通常在控制器级别执行。这确保你在应用程序处理请求后立即验证用户输入,并在响应中发送可以显示在表单字段旁边的错误。
验证完成后,你可以使用可信数据执行其余操作,如数据库查询、调度队列作业、发送电子邮件等。
选择验证库
AdonisJS 核心团队创建了一个框架无关的数据验证库,名为 VineJS。以下是使用 VineJS 的一些原因。
- 它是 Node.js 生态系统中最快的验证库之一。
- 提供静态类型安全以及运行时验证。
- 它与
web和api启动套件预配置。 - 官方 AdonisJS 包使用自定义规则扩展 VineJS。例如,Lucid 为 VineJS 贡献了
unique和exists规则。
然而,AdonisJS 在技术上不会强制你使用 VineJS。你可以使用任何适合你或你的团队的验证库。只需卸载 @vinejs/vine 包并安装你想使用的包。
配置 VineJS
使用以下命令安装和配置 VineJS。
另请参阅:VineJS 文档
node ace add vinejs使用验证器
VineJS 使用验证器的概念。你为应用程序可以执行的每个操作创建一个验证器。例如:为创建新文章定义一个验证器,为更新文章定义另一个验证器,也许为删除文章定义一个验证器。
我们将以博客为例,定义创建/更新文章的验证器。让我们首先注册几个路由和 PostsController。
// title: 定义路由
import router from '@adonisjs/core/services/router'
const PostsController = () => import('#controllers/posts_controller')
router.post('posts', [PostsController, 'store'])
router.put('posts/:id', [PostsController, 'update'])// title: 创建控制器
node ace make:controller post store update// title: 脚手架控制器
import { HttpContext } from '@adonisjs/core/http'
export default class PostsController {
async store({}: HttpContext) {}
async update({}: HttpContext) {}
}创建验证器
创建 PostsController 并定义路由后,你可以使用以下 ace 命令创建验证器。
另请参阅:Make validator 命令
node ace make:validator post验证器创建在 app/validators 目录中。验证器文件默认为空,你可以用它从中导出多个验证器。每个验证器是一个 const 变量,持有 vine.compile 方法的结果。
在下面的例子中,我们定义 createPostValidator 和 updatePostValidator。两个验证器的 schema 略有不同。在创建期间,我们允许用户为文章提供自定义 slug,而我们不允许更新它。
TIP
不要太担心验证器 schema 中的重复。我们建议你选择易于理解的 schema,而不是不惜一切代价避免重复。wet codebase 类比可能会帮助你接受重复。
// title: app/validators/post_validator.ts
import vine from '@vinejs/vine'
/**
* 验证文章的创建操作
*/
export const createPostValidator = vine.compile(
vine.object({
title: vine.string().trim().minLength(6),
slug: vine.string().trim(),
description: vine.string().trim().escape()
})
)
/**
* 验证文章的更新操作
*/
export const updatePostValidator = vine.compile(
vine.object({
title: vine.string().trim().minLength(6),
description: vine.string().trim().escape()
})
)在控制器中使用验证器
让我们回到 PostsController 并使用验证器来验证请求体。你可以使用 request.all() 方法访问请求体。
import { HttpContext } from '@adonisjs/core/http'
import {
createPostValidator,
updatePostValidator
} from '#validators/post_validator'
export default class PostsController {
async store({ request }: HttpContext) {
const data = request.all()
const payload = await createPostValidator.validate(data)
return payload
}
async update({ request }: HttpContext) {
const data = request.all()
const payload = await updatePostValidator.validate(data)
return payload
}
}使用 request.validateUsing 方法
你可以使用 request.validateUsing 方法使代码更简洁。此方法会自动将请求体和上传的文件传递给验证器。
import { HttpContext } from '@adonisjs/core/http'
import {
createPostValidator,
updatePostValidator
} from '#validators/post_validator'
export default class PostsController {
async store({ request }: HttpContext) {
const payload = await request.validateUsing(createPostValidator)
return payload
}
async update({ request }: HttpContext) {
const payload = await request.validateUsing(updatePostValidator)
return payload
}
}处理验证错误
如果验证失败,VineJS 会抛出 E_VALIDATION_ERROR 异常。AdonisJS 的全局异常处理程序会自动处理此异常,并使用内容协商将错误转换为 HTTP 响应。
- 对于服务器渲染的应用程序,错误消息会使用 session flashMessages 闪存并重定向回表单。
- 对于 JSON API,错误消息会作为 JSON 响应返回,状态码为
422。
错误消息
VineJS 允许你在定义验证 schema 时自定义错误消息。你可以使用 messages 方法定义消息。
const createPostValidator = vine.compile(
vine.object({
title: vine.string().trim().minLength(6),
slug: vine.string().trim(),
description: vine.string().trim().escape()
})
)
createPostValidator.messagesProvider = new SimpleMessagesProvider({
'required': '{{ field }} 字段是必需的',
'string': '{{ field }} 字段的值必须是字符串',
'title.minLength': '文章标题必须至少有 6 个字符',
})唯一性和存在性规则
当使用 Lucid ORM 时,你可以使用 unique 和 exists 规则来检查数据库中值的唯一性或存在性。
import vine from '@vinejs/vine'
const createUserValidator = vine.compile(
vine.object({
email: vine
.string()
.email()
.unique(async (db, value) => {
const user = await db.from('users').where('email', value).first()
return !user
}),
})
)条件验证
VineJS 支持条件验证,允许你根据其他字段的值动态更改验证规则。
import vine from '@vinejs/vine'
const validator = vine.compile(
vine.object({
accountType: vine.enum(['personal', 'business']),
companyName: vine
.string()
.optional()
.requiredWhen('accountType', '=', 'business'),
})
)表单请求验证
对于使用表单的 Web 应用程序,验证错误会自动闪存到会话中,你可以在 Edge 模板中访问它们。
<form method="POST" action="/posts">
<div>
<label for="title">标题</label>
<input type="text" name="title" value="{{ old('title', '') }}" />
@error('title')
<span class="error">{{ $message }}</span>
@end
</div>
<button type="submit">创建文章</button>
</form>