5
votes

Here's a proto definition for a service that consumes a stream of events from a client

message Event {
  // ...
}

service EventService {
  rpc Publisher(stream Event) returns (google.protobuf.Empty);
}

The problem is that the server needs to be told what to do with this stream. Ideally, it would first recieve an Options message:

message Event {
  // ...
}

message Options {
  // ...
}

service EventService {
  rpc Publisher(Options, stream Event) returns (google.protobuf.Empty);
}

However, grpc only supports one parameter for rpc methods. One solution is to introduce an additional PublishMessage message which can contain either an Options or Event message.

message PublishMessage {
  oneof content {
    Options options = 1;
    Event event = 2;
  }
}

The service would then expect the first PublishMessage to contain an Options message, with all subsequent ones containing Event messages. This introduces additional overhead from the wrapping message and makes the api a little clunky.

Is there a cleaner way to achieve the same result?

1

1 Answers

5
votes

Using oneof is the suggested approach when many fields or messages are in play. The overhead is minimal, so wouldn't generally be a concern. There is the clunkiness though.

If there's only a few fields, you may want to combine the fields from Options and Event into a single message. Or similarly add Options to Event as a field. You'd expect the Options fields to be present on the first request and missing from subsequent. This works better when there's fewer configuration fields, like just a "name."