ThanhLam112358
ThanhLam112358

Reputation: 916

Dynamic defined message in gRPC GO

I am a new user of gRPC in Go.

I have completed my code about client streaming API. And now I have a question.

With my knowledge, we must define message struct in proto file, then the protoc based on this defined message struct to generate code. In my case, protoc generate Go code. But this process limit the client or the server reuses API. For example, with client-streaming API, firstly, the client use this API to send temperature data to server. Then the client must re-defind message struct if the client want to send GPS coordinates to server, because the contruct of temperature is different from the contruct of GPS coordinates. But for the same purpose is send data to server.

syntax = "proto3";
package calculator;
option go_package="calculatorpb";
message TemperatureRequest{
     float num =1;
}
message TemperatureResponse{
     float result =1;
}
message CoordinatesRequest{
     float long =1;
     float lat =1;
}
message CoordinatesResponse{
     float result =1;
}
service  CalculatorService{
   rpc Temperature(stream AverageRequest) returns (AverageResponse){} //client streaming for temperature    
   rpc Coordinates(stream CoordinatesRequest) returns (CoordinatesResponse){} //client streaming  for  Coordinates
}

It seem be inconvenient.

So, how the client can use dynamic message struct with gRPC in go?

If yes, please give me an example of the client-streaming API.

Upvotes: 2

Views: 1820

Answers (3)

Doug Fawley
Doug Fawley

Reputation: 1111

It sounds like what you're asking for is:

syntax = "proto3";
package calculator;
option go_package="calculatorpb";

// message TemperatureRequest, TemperatureResponse, CoordinatesRequest, CoordinatesResponse defined as in your example

message DataRequest {
  TemperatureRequest temperature_request = 1;
  CoordinatesRequest coordinates_request = 2;
}
message DataResponse {
  TemperatureResponse temperature_response = 1;
  CoordinatesResponse coordinates_response = 2;
}

service  CalculatorService{
   rpc Data(stream DataRequest) returns (DataResponse){} //client streaming for data
}

Remember that DataRequest and DataResponse are extensible, so you can add fields to them in the future, if desired.

Upvotes: 0

sonus21
sonus21

Reputation: 5388

Use the Any message type:

syntax = "proto3";

import "google/protobuf/any.proto";

message Example {
    string id = 1;
    google.protobuf.Any message = 2;
}

With Any, you can use any user-defined proto message, also you need to share the new proto message with the client using some common repo or registry.

Upvotes: 3

keser
keser

Reputation: 2642

I am not sure that i understood your question properly, but i'll assume I have. Protobuf is a way to define communication protocol between two services, without limiting the underlying technology of those servers.

The code generated by protoc has only the purpose of communicating between services. If you want to have extra methods and stub code over them, you need wrapper structs on both ends. Because this is the idiomatic way to use protobuf

eg.

type MyStruct{

pb.Mystruct

}

func (m MyStruct) CalculateWeather() (int,error){

...

}


Normally, you should define different structs for each case. I am not sure what you want, but you could simply marshal your objects and send bytes over, and unmarshal back

Upvotes: 0

Related Questions