【发布时间】:2020-03-12 03:27:20
【问题描述】:
我正在使用 grpc protobuf 消息定义并在 Go 中实现它们。
我的最终目标是让我的 rpc 检索用户的一些 json 并返回一个 Profile 消息,其中包含用于解组 json 子集的可选嵌套消息。
使用这个 rpc:
rpc GetUser (GetUserRequest) returns (Profile) {
option (google.api.http) = {
get: "/user/{id=*}"
};
}
并假设以下json:
{
"profile": {
"foo": {
"name": "tim"
"age": 22
},
"bar": {
"level": 5
}
}
}
我想返回一个 Profile 消息,仅包含“foo”、“bar”或两者,作为基于传入运行时 scope grpc 请求参数的嵌套消息(目前,scope 将是包含消息名称的字符串列表,用于将 json 子集到相应的消息中,例如 ["Foo","Bar"])。
鉴于这些消息定义:
message Profile {
//both Foo & Bar are optional by default
Foo foo = 1 [json_name="foo"];
Bar bar = 2 [json_name="bar"];
}
message Foo {
string name = 1 [json_name="name"];
int32 age = 2 [json_name="age"];
}
message Bar {
string level = 1 [json_name="level"];
}
那么在scope 是["Foo"] 的情况下,我希望rpc 返回:
Profile{
Foo: // Foo Message unmarshalled from json
}
或者如果"scope" 是["Foo","Bar"] 那么:
Profile{
Foo:
Bar:
}
问题似乎归结为“鸭式”消息类型。
尝试 1
我已经接近使用protoreflect 和protoregistry 找到解决方案了:
import(
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/reflect/protoreflect"
)
var scope protoreflect.FullName = "Foo"
var types = new(protoregistry.Types)
var message, errs = types.FindMessageByName(scope)
var almost_foo = message.New()
// using `myJson` object without top level "profile" key to make testing more simple at the moment
var myJson = `{ "foo": { .. }, "bar", { ... } }`
err = json.Unmarshal([]byte(myJson), almost_foo)
但是当我尝试使用almost_foo 创建个人资料消息时:
var profile = &pb.Profile{almost_foo}
我收到错误:cannot use almost_foo (type protoreflect.Message) as type *package_name.Foo in field value
尝试 2
使用
import(
"github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/dynamic"
)
我尝试再次动态创建消息:
var fd, errs = desc.LoadFileDescriptor("github.com/package/path/..")
var message_desc = fd.FindMessage("Foo")
var almost_foo = dynamic.NewMessage(message_desc)
并发生类似的错误:
cannot use almost_foo (type *dynamic.Message) as type *package_name.Foo in field value
这两种尝试都几乎创建了一条消息,但类型系统仍然不允许实际使用任何一种。
感谢任何帮助。
【问题讨论】:
标签: json go protocol-buffers grpc duck-typing