作者 Oghenetega Denedo✏️
架构验证是任何生产就绪应用程序的必备条件,因为来自用户或其他外部源的任何数据都需要符合预定义的结构或格式,以维护数据完整性并防止应用程序中出现任何意外行为。
通常,当用户向网站提交表单或通过 HTTP 请求发送到 API 的有效负载时,开发人员必须对输入数据进行验证。然而,手动编写此验证逻辑可能会重复且耗时,这不利于开发人员的工作效率。
幸运的是,用于常见开发任务的库在 JavaScript 社区中几乎不是什么问题,模式验证也不例外。
在本文中,我们将通过评估 VineJS 和 Zod 的验证功能、性能、与工具的集成以及生态系统来比较它们。最后,您会发现,虽然 VineJS 具有出色的性能,但 Zod 的多功能性和强大的 TypeScript 集成使其成为大多数项目的更全面的选择。
VineJS 是一个现代 JavaScript/TypeScript 模式验证库,旨在轻量级、易于使用和高性能。
该项目源自 AdonisJS 验证器代码库,并已升级并作为独立库发布。 VineJS 专为在 Node.js 服务器端环境中使用而构建,尤其是在验证 API 传入请求以确保有效负载在进一步处理之前具有预期格式的场景。
VineJS 的一些主要功能包括:
在下一节中,我们将了解其中一些功能如何发挥作用。
让我们看看 VineJS 的一些模式验证功能。
处理用户输入或来自外部源的数据时,验证字符串、数字和布尔值等基本数据类型通常是第一步。 VineJS 通过其直观的 API 简化了这个过程。
例如,让我们验证用户的年龄:
import vine, { errors } from "@vinejs/vine"; // NOTE: VineJS is ESM only const ageSchema = vine.number().min(18).max(30); try { const output = await vine.validate({ schema: ageSchema, data: 21 }); console.log(output); } catch (error) { if (error instanceof errors.E_VALIDATION_ERROR) { console.log("validation error: age is invalid"); } else { console.log("an unexpected error occurred"); } }
在这个例子中,我们创建了一个简单的模式来验证输入是一个数字,并使用 min 和 max 方法来确保它在 18 到 30 之间。VineJS 提供了这些额外的验证规则来使验证更加精确。
有时,您需要在应用验证规则之前格式化输入数据。例如,如果您想确保输入字符串在验证之前转换为小写,您可以在架构中执行此操作:
const usernameSchema = vine .string() .toLowerCase() .minLength(3) .maxLength(15) .regex(/^[a-z0-9_]+$/); console.log(vine.validate({schema: nameSchema, data: "Bruce_Wayne"})) // logs bruce wayne
在此架构中,在检查其长度和格式之前,用户名会被转换为小写。
除了基本模式类型之外,VineJS 还提供对象和数组的验证,这使得它对于验证具有多个字段的表单或 API 有效负载特别有用。
让我们看看如何验证代表用户个人资料的对象:
const userProfileSchema = vine.object({ name: vine.string().minLength(3), email: vine.string().email(), age: vine.number().min(18).max(65).optional(), }); const output = await vine.validate({ schema: ageSchema, data: { name: "Jane Doe", email: "jane.doe@example.com", age: 29, }, }); // logs { name: 'Jane Doe', email: 'jane.doe@example.com', age: 29 }
在此示例中,我们为用户配置文件设置了一个架构,其中包含姓名、电子邮件和年龄字段。
通过使用 vine.object() 方法,我们可以根据给定的规则验证每个字段。默认情况下,vine.object 中的所有字段都是必需的,因此它们必须存在于正在验证的对象中。但是,我们已使用 option() 方法将年龄字段标记为可选,因此如果缺少该字段,验证也不会失败。
数组也可以类似处理:
const tagsSchema = vine .array(vine.string().minLength(2).maxLength(20)) .minLength(1) .maxLength(10); console.log( await vine.validate({ schema: tagsSchema, data: ["tech", "news", "coding"], }) ); // logs [ 'tech', 'news', 'coding' ]
在此示例中,架构确保数组中的每个项目都是长度在 2 到 20 个字符之间的字符串,并且数组本身必须包含 1 到 10 个元素。这对于验证标签或类别等列表特别有用。
预编译是 VineJS 的一个关键功能,它将模式转换为优化的 JavaScript 函数,可以重复用于验证,以帮助减少重复解析和验证模式的开销。这在生产环境中非常有用,可以提高性能。
要预编译模式,您可以使用 vine.compile() 方法:
const compiledSchema = vine.compile( vine.object({ username: vine.string().minLength(3).maxLength(30), password: vine.string().minLength(8), }) ); // Use the compiled schema to validate data console.log( await compiledSchema.validate({ username: "janedoe", password: "password123", }) );
预编译对于需要频繁验证的模式特别有用,例如高流量 API 端点中的模式。
由于 schema 将被编译成可重用的函数,因此解析和验证 schema 的重复过程就不再存在,这样 VineJS 就可以加快验证过程,使您的应用程序响应更快。
自定义错误消息有助于向用户提供更清晰的反馈,以便更轻松地识别和纠正错误。 VineJS 使用其内置的 SimpleMessagesProvider API 将错误消息定义为键值对。键可以是规则名称(即 required 和字符串)或特定的字段-规则组合,值是相应的错误消息。
SimpleMessagesProvider API 可以在全局、每个模式级别或在调用 validate 方法时进行配置。对于接下来的代码示例,我们将在全局范围内使用该 API。
例如,假设您想要自定义用户名和电子邮件字段的错误消息:
import vine, { errors } from "@vinejs/vine"; // NOTE: VineJS is ESM only const ageSchema = vine.number().min(18).max(30); try { const output = await vine.validate({ schema: ageSchema, data: 21 }); console.log(output); } catch (error) { if (error instanceof errors.E_VALIDATION_ERROR) { console.log("validation error: age is invalid"); } else { console.log("an unexpected error occurred"); } }
您还可以自定义嵌套字段或数组元素的消息。对于嵌套字段,请使用点表示法:
const usernameSchema = vine .string() .toLowerCase() .minLength(3) .maxLength(15) .regex(/^[a-z0-9_]+$/); console.log(vine.validate({schema: nameSchema, data: "Bruce_Wayne"})) // logs bruce wayne
对于数组元素,您可以使用通配符 (*) 来定位所有项目或指定索引:
const userProfileSchema = vine.object({ name: vine.string().minLength(3), email: vine.string().email(), age: vine.number().min(18).max(65).optional(), }); const output = await vine.validate({ schema: ageSchema, data: { name: "Jane Doe", email: "jane.doe@example.com", age: 29, }, }); // logs { name: 'Jane Doe', email: 'jane.doe@example.com', age: 29 }
VineJS 还允许您用更用户友好的标签替换字段名称。当代码中的字段名称不适合面向用户的消息时,这非常有用:
const tagsSchema = vine .array(vine.string().minLength(2).maxLength(20)) .minLength(1) .maxLength(10); console.log( await vine.validate({ schema: tagsSchema, data: ["tech", "news", "coding"], }) ); // logs [ 'tech', 'news', 'coding' ]
除了内置规则提供的功能之外,VineJS 还使开发人员能够创建自定义验证规则来满足您的特定需求。您可以在项目中使用这些自定义规则,方法是将它们实现为独立函数或将它们集成到预先存在的架构类中。
在 VineJS 中,自定义规则只是一个更新或验证字段值的函数。通常将三个参数传递给函数:要验证的值、规则可能需要的任何选项以及字段上下文。
例如,让我们创建一个名为 mongodbId 的自定义规则,用于检查字符串是否是有效的 MongoDB ObjectId:
const compiledSchema = vine.compile( vine.object({ username: vine.string().minLength(3).maxLength(30), password: vine.string().minLength(8), }) ); // Use the compiled schema to validate data console.log( await compiledSchema.validate({ username: "janedoe", password: "password123", }) );
为了使该规则在 VineJS 模式中可用,我们必须首先使用 vine.createRule 方法将其转换为 VineJS 兼容规则:
import vine, { SimpleMessagesProvider } from '@vinejs/vine'; vine.messagesProvider = new SimpleMessagesProvider({ 'required': 'You must provide a value for {{ field }}.', 'email': '{{ field }} needs to be a valid email address.', 'username.required': 'A username is required to continue.', });
为了进一步简化其使用,您可能需要将 mongodbId 方法直接添加到 VineString 类中,以从可链接的 API 中受益:
Zod 是一个 TypeScript 优先的模式验证库,既简单又强大。它使定义和执行数据结构和验证规则变得容易,并且它适用于前端和后端应用程序。
Zod 专为 TypeScript 设计,确保 TypeScript 项目的平滑集成和强类型推断。
Zod 的一些主要功能是:
Zod 使模式验证变得简单而灵活,让您可以轻松处理各种数据类型和验证需求。它的语法与 VineJS 非常相似,您将在接下来的部分中看到。
Zod 可以很好地处理字符串、数字、布尔值和日期等基本数据类型。
例如,让我们创建一个简单的模式来验证字符串和数字:
import vine, { errors } from "@vinejs/vine"; // NOTE: VineJS is ESM only const ageSchema = vine.number().min(18).max(30); try { const output = await vine.validate({ schema: ageSchema, data: 21 }); console.log(output); } catch (error) { if (error instanceof errors.E_VALIDATION_ERROR) { console.log("validation error: age is invalid"); } else { console.log("an unexpected error occurred"); } }
在此示例中,nameSchema 验证“Peter Parker”是一个字符串并通过,而ageResult 由于年龄低于 18 岁而失败。
处理对象和数组时,Zod 可以轻松定义数据的形状。例如,验证用户对象和标签列表可以像这样完成:
const usernameSchema = vine .string() .toLowerCase() .minLength(3) .maxLength(15) .regex(/^[a-z0-9_]+$/); console.log(vine.validate({schema: nameSchema, data: "Bruce_Wayne"})) // logs bruce wayne
在上面的示例中,userSchema 验证用户数据,tagSchema 检查数组是否仅包含字符串。数组验证失败,因为 123 不是字符串。
为了使验证反馈更有用并更简单地识别错误,Zod 还支持可配置的错误消息。
例如,如果年龄未满18岁,您可以设置个性化消息:
const userProfileSchema = vine.object({ name: vine.string().minLength(3), email: vine.string().email(), age: vine.number().min(18).max(65).optional(), }); const output = await vine.validate({ schema: ageSchema, data: { name: "Jane Doe", email: "jane.doe@example.com", age: 29, }, }); // logs { name: 'Jane Doe', email: 'jane.doe@example.com', age: 29 }
此处,验证失败,并抛出错误,并显示自定义错误消息“您必须年满 18 岁”。
Zod 提供了使用细化方法创建自定义验证逻辑的灵活性,这使您可以强制执行基本类型检查之外的规则。
例如要验证十六进制颜色代码,仅仅判断它是否是字符串是不够的;它还需要遵循一定的模式。以下是具体操作方法:
const tagsSchema = vine .array(vine.string().minLength(2).maxLength(20)) .minLength(1) .maxLength(10); console.log( await vine.validate({ schema: tagsSchema, data: ["tech", "news", "coding"], }) ); // logs [ 'tech', 'news', 'coding' ]
在此示例中,使用细化方法添加自定义验证逻辑,以确定字符串是否是由三个或六个字符(#RGB 或 #RRGGBB)组成的有效十六进制颜色代码。
VineJS 文档的基准测试表明,VineJS 是 Node.js 生态系统中最快的验证库之一,在简单对象验证和其他验证方面超越了 Yup 和 Zod。
如 VineJS 文档所示。
图表显示,VineJS 提供了卓越的性能,使其成为需要高性能的后端应用程序的良好解决方案。 Zod 运行良好,速度足以满足大多数用例。
TypeScript 支持在两者中都非常出色,但 Zod 在设计时考虑了 TypeScript,以使类型推断更加无缝。 VineJS 也支持 TypeScript,但集成程度不高,这使得 Zod 在 TypeScript 密集型项目中略占优势。
有了更多的资源、教程和插件,Zod 拥有了更大、更成熟的社区。然而,尽管 VineJS 较新、资源较少且社区较小,但由于其易于使用的 API 和注重性能的设计,预计它会进一步发展。
使用 VineJS 的主要缺点是它不适用于前端运行时。由于此限制,它不太适合需要客户端验证的应用程序。此外,它不支持 CommonJS,这对于使用它的项目来说可能是一个问题。它仅适用于 ECMAScript 模块 (ESM)。
但是,Zod 更加通用,支持两种主要的 JavaScript 模块系统,同时无论您运行代码的环境如何,它都能正常工作,这使得它更适合全栈项目。
除了 VineJS 和 Zod 之外,对于各种用例,还有一些其他用于模式验证的库也值得一提。
由于其易于使用,Yup 很受欢迎并经常用于前端验证,特别是与 React 和 Formik 等工具结合使用时。与 VineJS 或 Zod 相比,它可能无法在复杂的结构中发挥作用,但其可链接的 API 使开发模式变得简单。
Node.js 后端中经常使用的强大库称为 joi。尽管它的 API 感觉比 VineJS 和 Zod 的轻量级方法更重,但它提供了更大的灵活性并管理深度嵌套对象的复杂验证。对于需要复杂验证的服务器端应用程序来说,它是完美的。
速度和完整的 JSON 模式合规性是 AJV 的主要优先事项。尽管它缺乏 Zod 或 VineJS 所具有的用户友好的 API,但它对于验证 JSON 数据非常有用,尤其是在 API 中。但对于需要高效率的任务,比如验证庞大的 JSON 数据集,它是理想的选择。
VineJS 和 Zod 是两个优秀的模式验证工具,使用它们都不会出错,但它们在不同的领域表现出色。如果您仍然不确定使用哪一个,请在一个小项目中尝试它们,看看哪一个适合您。快乐编码!
调试代码始终是一项乏味的任务。但你越了解自己的错误,就越容易纠正它们。
LogRocket 允许您以新的、独特的方式理解这些错误。我们的前端监控解决方案跟踪用户与 JavaScript 前端的互动,使您能够准确查看用户的操作导致了错误。
LogRocket 记录控制台日志、页面加载时间、堆栈跟踪、带有标头正文的慢速网络请求/响应、浏览器元数据和自定义日志。了解 JavaScript 代码的影响从未如此简单!
免费试用。
以上是VineJS 与 Zod 进行模式验证的详细内容。更多信息请关注PHP中文网其他相关文章!