Lloen
Lloen

Reputation: 68

More efficient way to set a oneof request in gRPC/proto3

Having this proto3 schema on a PHP client and Python server:

service GetAnimalData{
    rpc GetData (AnimalRequest) returns (AnimalData) {}
}

message AnimalRequest {
    OneOfAnimal TypeAnimal = 1;
}

message AnimalData {
    repeated int32 data = 1;
}

message OneOfAnimal {
    oneof animal_oneof {
        CAT cat = 1;
        DOG dog = 2;
    }
}

message CAT{
    int32 p = 1;
    int32 d = 2;
    int32 q = 3;
}

message DOG{
    int32 p = 1;
    int32 d = 2;
    int32 q = 3;
    int32 p2 = 4;
    int32 d2 = 5;
    int32 q2 = 6;
}

In oder to set up a request from the PHP client, I need to do:

  1. Create a new CAT
  2. Set OneOfAnimal as CAT
  3. Set AnimalRequest.TypeAnimal as OneOfAnimal

Is there a schema for proto3 where I can just set either a CAT or DOG object directly as my AnimalRequest.TypeAnimal

Upvotes: 1

Views: 3835

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062510

In general terms; no, not really.

In some very specific cases, the answer is "yes" - for example, protobuf-net (a "code-first" protobuf implementation in .NET) happens to implement inheritance in exactly this way, so you could use:

[ProtoContract]
public class AnimalRequest {
    [ProtoMember(1)] public Animal Animal {get;set;}
}

[ProtoContract]
[ProtoInclude(1, typeof(Cat))]
[ProtoInclude(2, typeof(Dog))]
class Animal {} // acts identically to your OneOfAnimal message type

[ProtoContract]
class Cat {
    [ProtoMember(1)] public int P {get;set;}
    [ProtoMember(2)] public int D {get;set;}
    [ProtoMember(3)] public int Q {get;set;}
}

[ProtoContract]
class Dog {
    [ProtoMember(1)] public int P {get;set;}
    [ProtoMember(2)] public int D {get;set;}
    [ProtoMember(3)] public int Q {get;set;}
    [ProtoMember(4)] public int P2 {get;set;}
    [ProtoMember(5)] public int D2 {get;set;}
    [ProtoMember(6)] public int Q2 {get;set;}
}

and then you use:

var result = svc.GetData(
    new AnimalRequest { Animal = new Dog { P = 42, ... Q2 = 19 } }
);

and it would work exactly the same way - the same bytes would be sent; essentially, protobuf-net treats inheritance as oneof (at each level in the type hierarchy).

But: because .proto is intended to work in a very generic "least common denominator" way, .proto itself has no concept of inheritance, so: you can't do this from .proto or the Google libraries.

Upvotes: 4

Related Questions