gpt4 book ai didi

json - 如何在 Go 运行时创建 "duck-typed"grpc protobuf 消息?

转载 作者:行者123 更新时间:2023-12-01 22:17:07 25 4
gpt4 key购买 nike

我正在使用 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
两种尝试都几乎创建了一个 Message 但类型系统仍然不允许实际使用任何一种。

任何帮助表示赞赏。

最佳答案

我设法通过首先将 json 缩减为我想要的然后通过 Unmarshal 来解决这个问题。

我创建了一个顶级消息 Profile作为一个领域:

message GetUserResponse {
Profile profile = 1;
}

并重新定义了响应:
rpc GetUser (GetUserRequest) returns (GetUserResponse)

要构建允许/范围的 json,我使用:
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"

我将范围路径(点分隔,例如 ["profile.foo"] )指定的 json 复制到最初为空的输出 response_json字符串,并仅构建允许返回的 json。
var response_json string

var scopes = []string{"profile.foo"}

for _, scope := range scopes {
// copy allowed json subset in raw form
value := gjson.Get(myJson, scope + "|@ugly")

// if scope didn't copy a value, skip
if value.String() == "" {
continue
} else {
// write value to output json using SetRaw since value can be an object
response_json, _ = sjson.SetRaw(response_json, scope, value.Raw)
}
}

response_json 看起来像:
{
"profile": {
"foo": {
"name": "tim"
"age": 22
}
}
}

然后解码:
response = &pb.VerifyUserResponse{}
err = json.Unmarshal([]byte(response_json), response)

关于json - 如何在 Go 运行时创建 "duck-typed"grpc protobuf 消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58886124/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com