protovalidate
是一系列库,旨在根据用户定义的验证规则在运行时验证 Protobuf 消息。它由 Google 的通用表达式语言 (CEL) 提供支持,为定义和评估自定义验证规则提供了灵活高效的基础。 protovalidate
的主要目标是帮助开发人员确保整个网络中数据的一致性和完整性,而无需生成代码。
笔记
protovalidate
是 protoc-gen-validate 的精神继承者。它不需要生成任何代码并支持自定义约束。
我们建议新项目和现有项目过渡到使用protovalidate
而不是protoc-gen-validate
。
如果您想了解更多有关protoc-gen-validate
的局限性以及我们如何设计得更好的protovalidate
信息,请阅读我们的博客文章。
该存储库是protovalidate
项目的核心。它包含:
protovalidate
protoc-gen-validate
增量迁移protovalidate
的示例.proto
文件protovalidate
实现的验收测试protovalidate
的运行时实现可以在它们自己的存储库中找到:
protovalidate-go
(测试版)protovalidate-cc
(测试版)protovalidate-java
(测试版)protovalidate-python
(测试版)protovalidate-ts
(即将推出)有兴趣添加对另一种语言的支持吗?查看我们的贡献指南。
要在 Protobuf 消息中定义约束,请将buf/validate/validate.proto
导入到.proto
文件中:
syntax = "proto3" ;
package my.package ;
import "buf/validate/validate.proto" ;
buf
构建将buf.build/bufbuild/protovalidate
的依赖项添加到模块的buf.yaml
中:
version : v1
#
deps :
- buf.build/bufbuild/protovalidate
#
修改buf.yaml
后,不要忘记运行buf mod update
以确保您的依赖项是最新的。
protoc
构建将指向proto/protovalidate
目录内容的导入路径( -I
标志)添加到protoc
的调用中:
protoc
-I ./vendor/protovalidate/proto/protovalidate
#
可以使用buf.validate
Protobuf 包强制执行验证约束。规则直接在.proto
文件中指定。
让我们考虑几个例子:
标量字段验证:对于基本的User
消息,我们可以强制执行约束,例如用户名的最小长度。
syntax = "proto3" ;
import "buf/validate/validate.proto" ;
message User {
// User's name, must be at least 1 character long.
string name = 1 [ (buf.validate .field ) .string .min_len = 1 ];
}
地图字段验证:对于带有商品数量地图的Product
消息,我们可以确保所有数量均为正数。
syntax = "proto3" ;
import "buf/validate/validate.proto" ;
message Product {
// Map of item quantities, all quantities must be positive.
map < string , int32 > item_quantities = 1 [ (buf.validate .field ) .map.values.int32 .gt = 0 ];
}
众所周知的类型(WKT)验证:对于User
消息,我们可以添加一个约束来确保created_at
时间戳是过去的。
syntax = "proto3" ;
import "google/protobuf/timestamp.proto" ;
import "buf/validate/validate.proto" ;
message User {
// User's creation date must be in the past.
google.protobuf.Timestamp created_at = 1 [ (buf.validate .field ) .timestamp .lt_now = true ];
}
对于更高级或自定义约束, protovalidate
允许使用可以跨字段合并信息的 CEL 表达式。
字段级表达式:我们可以强制以字符串形式发送的产品price
包含货币符号,例如“$”或“£”。我们要确保价格为正且货币符号有效。
syntax = "proto3" ;
import "buf/validate/validate.proto" ;
message Product {
string price = 1 [ (buf.validate .field ).cel = {
id : "product.price" ,
message : "Price must be positive and include a valid currency symbol ($ or £)" ,
expression : "(this.startsWith('$') || this.startsWith('£')) && double(this.substring(1)) > 0"
}];
}
消息级表达式:对于Transaction
消息,我们可以使用消息级CEL表达式来确保delivery_date
始终在purchase_date
之后。
syntax = "proto3" ;
import "google/protobuf/timestamp.proto" ;
import "buf/validate/validate.proto" ;
message Transaction {
google.protobuf.Timestamp purchase_date = 1 ;
google.protobuf.Timestamp delivery_date = 2 ;
option (buf.validate .message ).cel = {
id : "transaction.delivery_date" ,
message : "Delivery date must be after purchase date" ,
expression : "this.delivery_date > this.purchase_date"
};
}
在表达式中生成错误消息:我们可以直接在 CEL 表达式中生成自定义错误消息。在此示例中,如果age
小于 18 岁,则 CEL 表达式的计算结果将是错误消息字符串。
syntax = "proto3" ;
import "buf/validate/validate.proto" ;
message User {
int32 age = 1 [ (buf.validate .field ).cel = {
id : "user.age" ,
expression : "this < 18 ? 'User must be at least 18 years old': ''"
}];
}
查看有关标准约束和自定义 CEL 约束的examples
。
使用约束注释消息后,使用受支持的语言库之一进行验证;无需生成额外的代码。
protovalidate
提供了一个强大的框架,通过对各种数据类型实施标准和自定义约束来验证 Protobuf 消息,并在发生验证违规时提供详细的错误信息。有关其所有组件、支持的约束以及如何有效使用它们的详细概述,请参阅我们的综合文档。关键组件包括:
标准约束: protovalidate
支持所有字段类型的广泛标准约束以及 Protobuf 众所周知类型的特殊功能。您可以将这些约束应用于 Protobuf 消息,以确保它们满足某些常见条件。
自定义约束:借助 Google 的通用表达式语言 (CEL), protovalidate
允许您创建复杂的自定义约束,以处理字段和消息级别的标准约束未涵盖的独特验证场景。
错误处理:发生违规时, protovalidate
会提供详细的错误信息,帮助您快速识别问题根源并修复问题。
protovalidate
是protoc-gen-validate
的精神继承者,提供原始插件中存在的所有相同功能,无需自定义代码生成,以及在 CEL 中描述复杂约束的新能力。
protovalidate
的约束非常接近地模拟protoc-gen-validate
中的约束,以确保开发人员轻松过渡。要从protoc-gen-validate
迁移到protovalidate
,请使用提供的迁移工具逐步升级您的.proto
文件。
根据 Apache 2 许可证提供。