Search code examples
flutterdartgrpcprotoc

Dart protoc Compilation Does Not Create gRPC Client Class


My issue is that I am unable to get client code for my .proto in dart. I have a .proto that I have compiled and tested in C#/.NET Core 7.0. I've successfully deployed the server to another machine, and have interacted with it from Visual Studio running my C# client. I would like to have a dart client so that I can have my flutter application interact with the server. It took a lot of struggle, but I was eventually able to figure out how to get the autogenerated code in dart. I had started by trying to use the Quick Start Guide, but wasn't making any progress. I was able to eventually get them after finding these things:

Figured out how to actually get protoc callable from this:

https://gayan-justo.medium.com/working-with-grpc-with-flutter-on-windows-17493528e6a2

Figured out how to actually get autogenerated files from the "Compiling Your Protocol Buffers" section in this:

https://protobuf.dev/getting-started/darttutorial/

My problem is now that I can't seem to figure out how to use the autogenerated classes for a client. The output is 4 files:

.pb.dart
.pbenum.dart
.pbjson.dart
.pbserver.dart

In all of the examples I can find online, everyone appears to call a a "Client" class that is autogenerated. I don't have any "Client" code in my autogenerated files. The closest thing I have is an Api class that takes an RpcClient (an abstract class) in to it's constructor. I thought maybe I could use the Client class from the grpc package but that doesn't inherit from RpcClient and doesn't work.

class GpioApi {
  $pb.RpcClient _client;
  GpioApi(this._client);

  $async.Future<TimedOnResponse> timedOn($pb.ClientContext? ctx, TimedOnRequest request) =>
    _client.invoke<TimedOnResponse>(ctx, 'Gpio', 'TimedOn', request, TimedOnResponse())
  ;
  $async.Future<TimedOffResponse> timedOff($pb.ClientContext? ctx, TimedOffRequest request) =>
    _client.invoke<TimedOffResponse>(ctx, 'Gpio', 'TimedOff', request, TimedOffResponse())
  ;
}

My hunch is that I've got to tell protoc to compile for Client instead of Server (which you can do in C# by updating a tag in your .csproj, but I cannot find the equivalent in flutter/dart and all my google searches keep giving me these examples that just have the autogenerated code with the client classes. Is this something I can specify in the .proto? Can anyone point me in the right direction?

This is my .proto:

syntax = "proto3";

package gpio;

service Gpio {
  rpc TimedOn (TimedOnRequest) returns (TimedOnResponse);
  rpc TimedOff (TimedOffRequest) returns (TimedOffResponse);
}

message TimedOnRequest {
  int32 pin = 1;
  double seconds = 2;
}

message TimedOnResponse {
  bool success = 1;  
  string message = 2;
}

message TimedOffRequest {
    int32 pin = 1;
}

message TimedOffResponse {
  bool success = 1;  
  string message = 2;
}
  

Solution

  • I figured it out. From the getting started tutorial I shared in my post, they have a line as such:

    protoc -I=$SRC_DIR --dart_out=$DST_DIR $SRC_DIR/gpio.proto

    I had to modify it like this:

    protoc -I=$SRC_DIR --dart_out=grpc:$DST_DIR $SRC_DIR/gpio.proto

    The output is:

    .pb.dart
    .pbenum.dart
    .pbgrpc.dart
    .pbjson.dart
    

    The .pbgrpc.dart has the Client class present in the examples.