首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Go中在运行时创建“鸭型”grpc原型消息?

如何在Go中在运行时创建“鸭型”grpc原型消息?
EN

Stack Overflow用户
提问于 2019-11-15 23:47:12
回答 1查看 659关注 0票数 0

我正在使用grpc消息定义并在Go中实现它们。

我的最终目标是检索用户上的一些json,并返回带有可选嵌套消息的Profile消息,用于解组json的子集。

使用此rpc:

代码语言:javascript
复制
  rpc GetUser (GetUserRequest) returns (Profile) {
    option (google.api.http) = {
      get: "/user/{id=*}"
    };
  }

并假设以下json:

代码语言:javascript
复制
{
  "profile": {
     "foo": {
        "name": "tim"
        "age": 22
      },
     "bar": {
       "level": 5
     }
  }
}

我希望返回一个只包含"foo“、"bar”或两者的Profile消息,作为基于grpc请求的传入运行时scope参数的嵌套消息(当前,scope将是一个字符串列表,其中包含用于将json添加到相应消息(例如["Foo","Bar"])中的消息名称)。

鉴于这些信息定义:

代码语言:javascript
复制
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返回:

代码语言:javascript
复制
Profile{
  Foo: // Foo Message unmarshalled from json
}

或者如果"scope"["Foo","Bar"],那么:

代码语言:javascript
复制
Profile{
  Foo: 
  Bar:
}

问题似乎归结为“鸭子输入”一种消息类型。

尝试1

通过以下操作,我接近于使用protoreflect & protoregistry找到解决方案:

代码语言:javascript
复制
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创建配置文件时

代码语言:javascript
复制
var profile = &pb.Profile{almost_foo}

我收到错误:cannot use almost_foo (type protoreflect.Message) as type *package_name.Foo in field value

企图2

使用

代码语言:javascript
复制
import(
  "github.com/jhump/protoreflect/desc"
  "github.com/jhump/protoreflect/dynamic"
)

我再次尝试动态地创建消息:

代码语言:javascript
复制
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

这两次尝试几乎都创建了一条消息,但类型系统仍然不允许实际使用。

任何帮助都是非常感谢的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-20 02:00:03

我设法解决了这个问题,将json压缩到了我首先想要的,然后将它提交给Un极权。

我创建了一个将Profile作为字段的顶级消息:

代码语言:javascript
复制
message GetUserResponse {
  Profile profile = 1;
}

并重新定义了答复:

代码语言:javascript
复制
rpc GetUser (GetUserRequest) returns (GetUserResponse)

要构建允许的/作用域的json,我使用:

代码语言:javascript
复制
"github.com/tidwall/gjson"
"github.com/tidwall/sjson"

我将由作用域路径(点分隔的例如["profile.foo"])指定的json复制到最初为空的输出response_json字符串,并且只构建要返回的允许的json。

代码语言:javascript
复制
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看起来像:

代码语言:javascript
复制
{
  "profile": {
     "foo": {
        "name": "tim"
        "age": 22
      }
  }
}

然后法警:

代码语言:javascript
复制
response = &pb.VerifyUserResponse{}
err = json.Unmarshal([]byte(response_json), response)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58886124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档