mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-27 23:12:20 +00:00
ch4-06: 完善细节
This commit is contained in:
parent
766aa42947
commit
2432290c6a
@ -19,7 +19,7 @@ message Message {
|
||||
}
|
||||
```
|
||||
|
||||
默认值语法内置其实是通过Protobuf的扩展选项特性实现。在第三版的Protobuf中不再支持默认值特性,但是我们可以通过扩展选项自己定制默认值。
|
||||
内置的默认值语法其实是通过Protobuf的扩展选项特性实现。在第三版的Protobuf中不再支持默认值特性,但是我们可以通过扩展选项自己模拟默认值特性。
|
||||
|
||||
下面是用proto3语法的扩展特性重新改写上述的proto文件:
|
||||
|
||||
@ -65,13 +65,13 @@ var E_DefaultInt = &proto.ExtensionDesc{
|
||||
|
||||
我们可以在运行时通过类似反射的技术解析出Message每个成员定义的扩展选项,然后从每个扩展的相关联的信息中解析出我们定义的默认值。
|
||||
|
||||
在开源社区中,github.com/mwitkow/go-proto-validators 基于Protobuf的扩展特性实现了功能较为强大的验证器功能。要使用该验证器首先需要下载其提供的代码生成插件:
|
||||
在开源社区中,github.com/mwitkow/go-proto-validators 已经基于Protobuf的扩展特性实现了功能较为强大的验证器功能。要使用该验证器首先需要下载其提供的代码生成插件:
|
||||
|
||||
```
|
||||
$ go get github.com/mwitkow/go-proto-validators/protoc-gen-govalidators
|
||||
```
|
||||
|
||||
然后基于go-proto-validators验证器重新定义上述的Message成员的验证规则:
|
||||
然后基于go-proto-validators验证器的规则为Message成员增加验证规则:
|
||||
|
||||
```protobuf
|
||||
syntax = "proto3";
|
||||
@ -81,14 +81,18 @@ package main;
|
||||
import "github.com/mwitkow/go-proto-validators/validator.proto";
|
||||
|
||||
message Message {
|
||||
string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}];
|
||||
int32 age = 2 [(validator.field) = {int_gt: 0, int_lt: 100}];
|
||||
string important_string = 1 [
|
||||
(validator.field) = {regex: "^[a-z]{2,5}$"}
|
||||
];
|
||||
int32 age = 2 [
|
||||
(validator.field) = {int_gt: 0, int_lt: 100}
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
在方括弧表示的成员扩展中,validator.field表示扩展是validator包中定义的名为field扩展选项。validator.field的类型是FieldValidator结构体,在导入的validator.proto文件中定义。
|
||||
|
||||
validator.proto文件的内容如下:
|
||||
所有的验证规则都由validator.proto文件中的FieldValidator定义:
|
||||
|
||||
```protobuf
|
||||
syntax = "proto2";
|
||||
@ -112,9 +116,9 @@ message FieldValidator {
|
||||
}
|
||||
```
|
||||
|
||||
从FieldValidator定义的注释中我们可以知道验证器扩展的一些语法:其中regex表示用于字符串验证的正则表达式,int_gt和int_lt表示数值的范围。
|
||||
从FieldValidator定义的注释中我们可以看到验证器扩展的一些语法:其中regex表示用于字符串验证的正则表达式,int_gt和int_lt表示数值的范围。
|
||||
|
||||
采用以下的命令生成验证函数代码:
|
||||
然后采用以下的命令生成验证函数代码:
|
||||
|
||||
```
|
||||
protoc \
|
||||
@ -125,26 +129,33 @@ protoc \
|
||||
hello.proto
|
||||
```
|
||||
|
||||
以上的命令会调用protoc-gen-govalidators程序,生成一个名为hello.validator.pb.go的代码:
|
||||
以上的命令会调用protoc-gen-govalidators程序,生成一个独立的名为hello.validator.pb.go的文件:
|
||||
|
||||
```go
|
||||
var _regex_Message_ImportantString = regexp.MustCompile("^[a-z]{2,5}$")
|
||||
|
||||
func (this *Message) Validate() error {
|
||||
if !_regex_Message_ImportantString.MatchString(this.ImportantString) {
|
||||
return go_proto_validators.FieldError("ImportantString", fmt.Errorf(`value '%v' must be a string conforming to regex "^[a-z]{2,5}$"`, this.ImportantString))
|
||||
return go_proto_validators.FieldError("ImportantString", fmt.Errorf(
|
||||
`value '%v' must be a string conforming to regex "^[a-z]{2,5}$"`,
|
||||
this.ImportantString,
|
||||
))
|
||||
}
|
||||
if !(this.Age > 0) {
|
||||
return go_proto_validators.FieldError("Age", fmt.Errorf(`value '%v' must be greater than '0'`, this.Age))
|
||||
return go_proto_validators.FieldError("Age", fmt.Errorf(
|
||||
`value '%v' must be greater than '0'`, this.Age,
|
||||
))
|
||||
}
|
||||
if !(this.Age < 100) {
|
||||
return go_proto_validators.FieldError("Age", fmt.Errorf(`value '%v' must be less than '100'`, this.Age))
|
||||
return go_proto_validators.FieldError("Age", fmt.Errorf(
|
||||
`value '%v' must be less than '100'`, this.Age,
|
||||
))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
也就是为Message结构体增加了一个Validate方法,用于验证该成员是否满足Protobuf中定义的条件约束。
|
||||
生成的代码为Message结构体增加了一个Validate方法,用于验证该成员是否满足Protobuf中定义的条件约束。无论采用何种类型,所有的Validate方法都用相同的签名,因此可以满足相同的验证接口。
|
||||
|
||||
通过生成的验证函数,并结合GRPC的截取器,我们可以很容易为每个方法的输入参数和返回值进行验证。
|
||||
|
||||
@ -237,7 +248,7 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
首先通过runtime.NewServeMux()函数创建路由处理器,然后通过RegisterRestServiceHandlerFromEndpoint函数将RestService服务相关的REST接口导到后面的GRPC服务。grpc-gateway提供runtime.ServeMux类似同时也实现了http.Handler接口,因此可以标准库中的相关函数配置使用。
|
||||
首先通过runtime.NewServeMux()函数创建路由处理器,然后通过RegisterRestServiceHandlerFromEndpoint函数将RestService服务相关的REST接口中转到后面的GRPC服务。grpc-gateway提供runtime.ServeMux类似同时也实现了http.Handler接口,因此可以标准库中的相关函数配置使用。
|
||||
|
||||
档GRPC和REST服务全部启动之后,就可以用curl请求REST服务了:
|
||||
|
||||
@ -254,8 +265,8 @@ $ curl localhost:8080/post -X POST --data '{"value":"grpc"}'
|
||||
```
|
||||
$ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
|
||||
|
||||
$ protoc \
|
||||
-I=. -I=../../../github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
|
||||
$ protoc -I. \
|
||||
-I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
|
||||
--swagger_out=. \
|
||||
hello.proto
|
||||
```
|
||||
|
Loading…
x
Reference in New Issue
Block a user