Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

grpc Protobuff 3 nested message definitions

I would like to define my messages in a nested way like this:

FooRequest

  • messageId
  • correlationId
  • moreFields
  • payload (dedicated proto containing the Foo payload)

And use the Requests in my grpc service defintions like this:

service SessionManager {
    rpc CreateSession (CreateSessionRequest) returns (CreateSessionResponse) {}
    rpc DropSession (DropSessionRequest) returns (DropSessionResponse) {}
}

For this it would be nice to define the Request proto only once and re-use it for all the Requests I want to create.

message Request {
    string messageId = 1;
    string origin = 2;
    string correlationId = 3;
    int32 sentAt = 4;
    string type = 5;
    int32 version = 6;
    google.protobuf.Any metadata = 7;
    google.protobuf.Any payload = 8;
}

Instead of doing this:

message CreateSessionRequest {
    string messageId = 1;
    string origin = 2;
    string correlationId = 3;
    int32 sentAt = 4;
    string type = 5;
    int32 version = 6;
    google.protobuf.Any metadata = 7;
    CreateSessionPayload payload = 8;
}

message DropSessionRequest {
    string messageId = 1;
    string origin = 2;
    string correlationId = 3;
    int32 sentAt = 4;
    string type = 5;
    int32 version = 6;
    google.protobuf.Any metadata = 7;
    DropSessionPayload payload = 8;
}

Is this somehow possible?

like image 632
leozilla Avatar asked Oct 16 '22 06:10

leozilla


1 Answers

This is definitely possible, though there are some other ways to do it. You can factor the common fields into a single message, which is included in each of your requests / responses:

message CommonRequestFields {
  string messageId = 1;
  string origin = 2;
  string correlationId = 3;
  int32 sentAt = 4;
  string type = 5;
  int32 version = 6;
}

You can include this as a formal field on each request message type, without needing to depend on Any:

message CreateSessionRequest {
  CommonRequestFields common = 1;
  Session session = 2;
  // ...
}

message DropSessionRequest {
  CommonRequestFields common = 1;
  string sessionId = 2;
  // ...
}

This approach has several upsides:

  • It's easy to add common fields for each request
  • You can handle each request common fields the same way on the client and server
  • Field IDs and names don't interfere with the request-specific fields IDs and names

However, there are some downsides:

  • You need to check the common fields are present, rather than directly accessing the field
  • Some requests may not need all the common fields, causing message bloat
  • What is common today may not be common in 6 months as requirements change.

Lastly, if you are using gRPC, you can send Metadata along with each request, which lives outside of the request body. Metadata fields are String key-value pairs (same as HTTP headers) and may be appropriate if you are sending them for every requests or response. You can even encode protos as header fields, though this may require some more advanced API usage.

like image 69
Carl Mastrangelo Avatar answered Oct 24 '22 13:10

Carl Mastrangelo