表单验证简介
AdonisJS
对请求体的 解析 和 验证 有一流的支持,无需安装第三方包,只需定义验证声明并根据它验证请求体。
import Route from '@ioc:Adonis/Core/Route'
import { schema } from '@ioc:Adonis/Core/Validator'
Route.post('posts', async ({ request }) => {
/**
* Schema definition
*/
const newPostSchema = schema.create({
title: schema.string(),
body: schema.string(),
categories: schema.array().members(schema.number()),
})
/**
* 根据声明验证请求正文
*/
const payload = await request.validate({ schema: newPostSchema })
})
验证器还从声明定义中 提取静态类型,您可以从单个声明定义中获得运行时验证和静态类型安全性。
Schema composition#
声明定义分为三个主要部分。
schema.create
方法定义了您期望的数据的形状。schema.string
,schema.number
,和其他类型方法定义单个字段的数据类型。- 最后,您使用
rules
对象在给定字段上应用额外的验证约束,例如:验证字符串是否为有效电子邮件并在数据库中是唯一的。
注:
rules
对象是从@ioc:Adonis/Core/Validator
导入的。
import { schema, rules } from '@ioc:Adonis/Core/Validator'
如果您仔细看,我们将 格式验证 与 核心数据类型 分开,例如,没有称为 schema.email
的数据类型,我们使用 rules.email
方法来确保字符串格式化为电子邮件。
这种分离有助于使用自定义规则扩展验证器,而不会创建不必要的模式类型。例如,没有所谓的 email type;它只是一个字符串,格式为电子邮件。
使用可选值和 null#
默认情况下,所有字段都是必填。但是,可以使用 optional
、nullable
和 nullableAndOptional
修饰符将字段标记为可选和可空。
所有这些修饰符都有不同的用途,详情如下:
修饰符 | 验证行为 | 返回结果 |
---|---|---|
optional |
允许 null 和 undefined 值同时存在 |
返回值中对应项可以不存在 |
nullable |
允许存在 null 值。但是,该字段必须在验证数据中存在声明 |
返回包含 null 的字段值 |
nullableAndOptional |
允许 null 和 undefined 值同时存在。 (与修饰符 1 相同) |
仅当值未定义时不返回键,否则返回字段值 |
nullable
修饰符#
你经常会发现自己使用 nullable
修饰符来允许在表中使用可选字段。
在以下示例中,当用户为 fullName
字段提交空值时,服务器将收到 null
,因此你可以将数据库中现有的全名更新为 null。
schema: schema.create({
fullName: schema.string.nullable(),
})
nullableAndOptional
修饰符#
如果你创建的 API 服务器接受 PATCH 请求并允许客户端更新资源的一部分,则必须使用 nullableAndOptional
修饰符。
在下面的例子中,如果 fullName
是未定义的,你可以假设客户端不想更新这个属性,如果是 null
,他们则想要设置属性值 null
。
const payload = await request.validate({
schema: schema.create({
fullName: schema.string.nullableAndOptional(),
})
})
const user = await User.findOrFail(1)
user.merge(payload)
await user.save()
optional
修饰符#
optional
修饰符在你想要更新没有任何可选字段资源的一部分时很有用。
email
属性在以下示例中可能存在也可能不存在。但是用户不能设置它为 null
。如果该属性不在请求中,你将不会更新邮件字段。
const payload = await request.validate({
schema: schema.create({
email: schema.string.optional(),
})
})
const user = await User.findOrFail(1)
user.merge(payload)
await user.save()
验证 HTTP 请求#
您可以使用 request.validate
方法验证给定 HTTP 请求的请求正文、查询字符串和路由参数。如果失败,validate
方法将抛出异常。
import Route from '@ioc:Adonis/Core/Route'
import { schema, rules } from '@ioc:Adonis/Core/Validator'
Route.post('users', async ({ request, response }) => {
/**
* 第 1 步 - 定义架构
*/
const newUserSchema = schema.create({
username: schema.string(),
email: schema.string([
rules.email()
]),
password: schema.string([
rules.confirmed(),
rules.minLength(4)
])
})
try {
/**
* 第 2 步 - 验证架构下的请求正文
*/
const payload = await request.validate({
schema: newUserSchema
})
} catch (error) {
/**
* 第 3 步 - 处理错误
*/
response.badRequest(error.messages)
}
})
我们建议 不要自行处理 异常而是让 AdonisJS 使用内容协商转换异常 到响应正文。
以下是内容协商如何工作的说明。
服务器渲染#
如果你使用服务器端模板构建标准 Web 应用程序,我们会将客户端重定向回表单并将错误作为会话闪存消息传递。
以下是会话闪存存储中错误消息的结构。
{
errors: {
username: ['username is required']
}
}
你可以使用 flashMessages
进行全局访问。
@if(flashMessages.has('errors.username'))
<p> {{ flashMessages.get('errors.username') }} </p>
@end
带有 Accept=application/json
请求头的请求#
协商 JSON 数据类型的请求以对象数组的形式接收错误消息,每条错误消息都包含字段名称、失败的验证规则和错误消息。
{
errors: [
{
field: 'title',
rule: 'required',
message: 'required validation failed',
},
]
}
JSON API#
使用 Accept=application/vnd.api+json
请求头协商的请求,根据 JSON API 规范 接收错误消息。
{
errors: [
{
code: 'required',
source: {
pointer: 'title',
},
title: 'required validation failed'
}
]
}
单独使用验证器#
你还可以通过从 Validator 模块导入 validate
方法在 HTTP 请求之外使用验证器。功能 API 保持不变。但是,你必须手动提供 data
进行验证。
import { validator, schema } from '@ioc:Adonis/Core/Validator'
await validator.validate({
schema: schema.create({
// ... 定义结构
}),
data: {
email: 'virk@adonisjs.com',
password: 'secret'
}
})
此外,由于你在 HTTP 请求之外执行验证,因此必须手动处理异常并显示错误。
验证器类#
验证器类允许您从控制器中提取内联模式并将它们移动到专用类。
您可以通过执行以下 Ace
命令来创建新的验证器。
node ace make:validator CreateUser
# 创建: app/Validators/CreateUserValidator.ts
所有与验证相关的属性,包括 schema
,messages
都被定义为类的属性。
// title: app/Validators/CreateUserValidator.ts
import { schema, CustomMessages } from '@ioc:Adonis/Core/Validator'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class CreateUserValidator {
constructor (protected ctx: HttpContextContract) {
}
public schema = schema.create({
})
public messages: CustomMessages = {}
}
使用验证器#
您现在可以将类构造函数传递给 request.validate
方法,而不是传递具有 schema
属性的对象。
import Route from '@ioc:Adonis/Core/Route'
// highlight-start
import CreateUser from 'App/Validators/CreateUserValidator'
// highlight-end
Route.post('users', async ({ request, response }) => {
// highlight-start
const payload = await request.validate(CreateUser)
// highlight-end
})
在验证期间,会在后台创建验证器类的实例,此外,request.validate
方法会将当前 HTTP 上下文作为第一个构造函数参数传递。
您还可以手动构造类实例并传递您喜欢的任何参数,例如:
Route.post('users', async ({ request, response }) => {
const payload = await request.validate(
new CreateUser({
countries: fetchAllowedCountries(),
states: fetchAllowedStates()
})
)
})
以下是在 HTTP 请求之外使用验证器类的示例。
import { validator } from '@ioc:Adonis/Core/Validator'
import CreateUser from 'App/Validators/CreateUserValidator'
await validator.validate(
new CreateUser({
countries: fetchAllowedCountries(),
states: fetchAllowedStates()
})
)
下一步是什么?#
- 阅读关于 验证服务器呈现的表单 的手册
- 了解更多关于 自定义消息
- 了解有关 错误报告
- 查看所有 可用的声明类型
- 查看所有 可用的验证规则
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。