Marshal/Unmarshal google.protobuf.Any proto message

4.9k Views Asked by At

I'm currently using gRPC for my API communication. Now I need the value of my request can accept any data type, be it a struct object or just a primitive data type like single integer, string, or boolean. I tried using google.protobuf.Any as below but it doesn't work when I want to marshal and unmarshal it.

message MyRequest {
    google.protobuf.Any item = 1; // could be 9, "a string", true, false, {"key": value}, etc.
}

proto-compiled result:

type MyRequest struct {
    Item *anypb.Any `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"`
}

I will marshal the incoming request through gRPC and save it as a JSON string in the database:

bytes, err = json.Marshal(m.request.Item)
if err != nil {
    return err
}
itemStr := string(bytes)

But when I want to unmarshal the string back into *anypb.Any by:

func getItem(itemStr string) (structpb.Value, error) {
    var item structpb.Value
    err := json.Unmarshal([]byte(itemStr), &item)
    
    if err != nil {
        return item, err
    }

    // also I've no idea on how to convert `structpb.Value` to `anypb.Any`
    return item, nil
}

It returns an error which seems to be because the struct *anypb.Any doesn't contain any of the fields in my encoded item string. Is there a correct way to solve this problem?

1

There are 1 best solutions below

2
On

Consider using anypb

In the documentation it shows an example of how to unmarshal it

m := new(foopb.MyMessage)
if err := any.UnmarshalTo(m); err != nil {
    ... // handle error
}
... // make use of m