Reputation: 916
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
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
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
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