protovalidate-go 调研&应用
背景:
- protovalidate-go 库支持在proto 文件中自定义返回的message
- protoc-gen-validate(PGV ) 已进入维护阶段,也需要考虑技术问题
使用:
下载:https://github.com/bufbuild/protovalidate/blob/main/proto/protovalidate/buf/validate/validate.proto 文件
将该文件放置在proto文件目录中
Proto 文件样例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24syntax = "proto3";
package my.package;
import "google/protobuf/timestamp.proto";
import "buf/validate/validate.proto";
option go_package = "api/v1;v1";
message Transaction {
uint64 id = 1 [(buf.validate.field).uint64.gt = 999];
google.protobuf.Timestamp purchase_date = 2;
google.protobuf.Timestamp delivery_date = 3;
string price = 4 [(buf.validate.field).cel = {
id: "transaction.price",
message: "price must be positive and include a valid currency symbol ($ or £)",
expression: "(this.startsWith('$') || this.startsWith('£')) && double(this.substring(1)) > 0"
}];
option (buf.validate.message).cel = {
id: "transaction.delivery_date",
message: "delivery date must be after purchase date",
expression: "this.delivery_date > this.purchase_date"
};
}可以在字段上添加验证规则,如上述示例中的
uint64.gt
和cel
规则
也可以在message上添加验证规则,如上述示例中的cel
规则
对应的验证规则可以在expression中定义。
message中的可以定义报错信息生成代码:
1
protoc --proto_path=. --proto_path=third_party --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative my/package/*.proto
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package main
import (
"fmt"
v1 "protovalidate-go-demo/api/v1"
"github.com/bufbuild/protovalidate-go"
)
func main() {
msg := &v1.Transaction{
Id: 123,
Price: "123.45",
}
if err := protovalidate.Validate(msg); err != nil {
fmt.Println("validation failed:", err)
} else {
fmt.Println("validation succeeded")
}
}运行结果:
1
2
3
4validation failed: validation error:
- delivery date must be after purchase date [transaction.delivery_date]
- id: value must be greater than 999 [uint64.gt]
- price: price must be positive and include a valid currency symbol ($ or £) [transaction.price]
CEL(通用表达式语言) 语法说明
具体可以这里:https://github.com/google/cel-spec/blob/master/doc/langdef.md
在这个库中,需要使用 CEL 进行规则编写(很多时候可以问ChatGpt)。
这里展示一些例子:
1 |
|
Kratos 中使用
- 在Kratos中,可以在中间件中使用该库进行参数校验
中间件:
1 |
|
迁移:
官方迁移向导:https://github.com/bufbuild/protovalidate/tree/main/tools/protovalidate-migrate
- 如中间件代码:在初始化validator时增加 legacy.WithLegacySupport(legacy.ModeMerge),就可以兼容validate/validate.proto;
- 如果不使用迁移,则PGV规则将无法生效
对比PGV优势
- 可自定义msg内容
- 可以同时返回多个不符合校验规则的消息,而PGV只能返回一个消息,如果有多个字段出现问题,那则需要多次调试
- 不会生成额外文件
- CEL 通用表示语言有很强大的扩展性,而且带有很多函数,实现逻辑判断
参考:
protovalidate-go 调研&应用
https://blog.codefish.net/2025/01/13/package-demo-GoPackage-protovalidate-go/