unmarshal yaml to proto3 with oneOf protobuf field

Viewed 2586

I have a proto message with a structure like this:

syntax = "proto3";

message Bar {
  int64 id = 1;
  string name = 2;
  int64 value = 3;
}

message Msg {
  int32 baz = 1;
  oneof some_union {
     string foo = 2;
     Bar bar = 3;
  }
}

I could think of two approaches to write yaml equivalent of the message. In the first approach, see below example, it assigns "some_union": null and no value is set in the field "foo".

baz: 0
foo: "some_string"

In the second approach, see below example, it throws an error saying cannot unmarshal object into Go struct field

baz: 0
some_union:
  foo: "some_string"

I am using github.com/ghodss/yaml package for unmarshlling yaml into proto message.

1 Answers

tl;dr;

You need to use protojson.Unmarshal to get the values from a oneOf field correctly.


I created the following proto definition

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;
  oneof avatar {
    string imageUrl = 4;
    bytes imageData = 5;
  }
}

Then I was able to create a YAML file like, which gets read correctly.

---
name: Harry Potter
id: 1
email: harry@potter.com
imageUrl: https://picsum.photos/id/1005/200

The only problem is, if I do the following,

yamlBytes, _ := ioutil.ReadFile("testdata/person.yaml")
person := &pb.Person{}
yaml.Unmarshal(yamlBytes, person)

The value of imageUrl is not set, just like you mention.

You need to do this - first convert the YAML to JSON, then use protojson.Unmarshal

yamlBytes, _ := ioutil.ReadFile("testdata/person.yaml")
person := &pb.Person{}
jsonBytes, _ := yaml.YAMLToJSON(yamlBytes)
protojson.Unmarshal(jsonBytes, person)

Then you have the proper value of imageUrl set.

Here is the link to the full code - https://github.com/mbtamuli/GoLearnGo/tree/master/protobufs. You can see it in action in here - https://replit.com/@mbtamuli/didactic-train

Related