我正在使用grpc消息定义并在Go中实现它们。
我的最终目标是检索用户上的一些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
}
}
}我希望返回一个只包含"foo“、"bar”或两者的Profile消息,作为基于grpc请求的传入运行时scope参数的嵌套消息(当前,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
这两次尝试几乎都创建了一条消息,但类型系统仍然不允许实际使用。
任何帮助都是非常感谢的。
发布于 2019-11-20 02:00:03
我设法解决了这个问题,将json压缩到了我首先想要的,然后将它提交给Un极权。
我创建了一个将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)https://stackoverflow.com/questions/58886124
复制相似问题