Best way to model gRPC messages

Viewed 495

I would like to model messages for bidirectional streaming. In both directions I can expect different types of messages and I am unsure as to what the better practice would be. The two ideas as of now:

message MyMessage {
    MessageType type = 1;
    string payload = 2;
}

In this case I would have an enum that defines which type of message that is and a JSON payload that will be serialized and deserialized into models both client and sever side. The second approach is:

 message MyMessage {
    oneof type {
        A typeA = 1;
        B typeB = 2;
        C typeC = 3;
    }
}

In the second example a oneof is defined such that only one of the message types can be set. Both sides a switch must be made on each of the cases (A, B, C or None).

1 Answers

If you know all of the possible types ahead of time, using oneof would be the way to go here as you have described.

The major reason for using protocol buffers is the schema definition. With the schema definition, you get types, code generation, safe schema evolution, efficient encoding, etc. With the oneof approach, you will get these benefits for your nested payload.

I would not recommend using string payload since using a string for the actual payload removes many of the benefits of using protocol buffers. Also, even though you don't need a switch statement to deserialize the payload, you'll likely need a switch statement at some point to make use of the data (unless you're just forwarding the data on to some other system).

Alternative option

If you don't know the possible types ahead of time, you can use the Any type to embed an arbitrary protocol buffer message into your message.

import "google/protobuf/any.proto";

message MyMessage {
  google.protobuf.Any payload = 1;
}

The Any message is basically your string payload approach, but using bytes instead of string.

message Any {
  string type_url = 1;
  bytes value = 2;
}

Using Any has the following advantages over string payload:

  • Encourages the use of protocol buffer to define the dynamic payload contents
  • Tooling in the protocol buffer library for each language for packing and unpacking protocol buffer messages into the Any type

For more information on Any, see:

Related