Create a Flutter gRPC client

In this post, we will address how to create a gRPC client in Flutter and connect to a Server. In order to test our client application, we will quickly build a gRPC service using .Net.

gRPC Server (C# .Net)

Let us use the Asp.Net core gRPC Service template provided by Visual Studio.

With the basic template in place, let us now go ahead and create our gRPC Protocol Buffers.

syntax = "proto3";

option csharp_namespace = "GrpcDemoServer";

package greet;

service Instrument{
	rpc ReadStatus (ReadStatusRequest) returns (ReadStatusResponse);
}

message ReadStatusRequest {
	int32 id = 1;
}

message ReadStatusResponse{
	string status = 1;
}


As observed in the above definition, we have a single service, namely Instrument, which has a single RPC method exposed – ReadStatus. The method accepts a ReadStatusRequest type as parameter and returns ReadStatusResponse type.

The ReadStatusRequest and ReadStatusResponse is defined as the following.

message ReadStatusRequest {
	int32 id = 1;
}

message ReadStatusResponse{
	string status = 1;
}

We will now create the corresponding service in our C# project.

publicclassInstrumentService: Instrument.InstrumentBase
{
    public override Task<ReadStatusResponse> ReadStatus(ReadStatusRequest request, ServerCallContext context)
    {
        return Task.FromResult(new ReadStatusResponse
        {
            Status = $"Connected : {TimeOnly.FromDateTime(DateTime.Now).ToLongTimeString()}"
        }) ;
    }
}

The key point to not here is that our InstrumentService class inherits from the Instrument.InstrumentBase class, which is the compiler generated code based on our protocol buffers defined earlier. The service itself doesn’t do much (to keep it simple for sake of example). It returns a string with the current TimeStamp.

Notice the usage of new TimeOnly data type. This stores the Time only information, a good addition to the language, which was previously limited by the DateTime data type.

The final step towards completing our service involves mapping the incoming requests to the InstrumentService. This can be done as the following.

app.MapGrpcService<InstrumentService>();

That is all we need to as far as our server is concerned. Before we proceed to the defining our client code, do not forget to look at your launchSetttings.json to get the port number in which the service would be running at.

{"profiles":{"GrpcDemoServer":{"commandName":"Project","dotnetRunMessages":true,"launchBrowser":true,"applicationUrl":"http://localhost:5280;https://localhost:7280","environmentVariables":{"ASPNETCORE_ENVIRONMENT":"Development"}}}}

We can now proceed to develop our client in flutter.

gRPC Client (Flutter/Dart)

Before we begin writing code for our Flutter Client, we need to add the protocol buffers defined earlier in our server to the client. Once added, we need use the protoc compliler to the generate the associated dart definitions. For installing the Protoc compiler, please refer the official documentation here

protoc --dart_out=grpc:lib\generated -Iprotos protos\greet.proto

This would generate the following files

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

For the sake of example, we will keep the flutter code as simple as possible. We will need a button, which the Users can use to request the client to connect and invoke the method exposed in the server.

floatingActionButton: FloatingActionButton(
        onPressed: sendRequest,
        tooltip: 'Send Request',
        child: const Icon(Icons.arrow_forward),
      )

The next obvious step is to define the sendRequest method which would send the actual request to the server. We would need to import the grpc.dart package for the purpose.

import'package:grpc/grpc.dart';

Also ensure it is added in the dependencies list in pubsec.yaml.

dependencies:flutter:sdk:fluttergrpc:^3.0.2

With that in place, let us now define out sendRequest method.

var _message = "";
late InstrumentClient stub;

Future<void> sendRequest() async {
final channel = ClientChannel('localhost',
    port: 5280,
    options:
        const ChannelOptions(credentials: ChannelCredentials.insecure()));

stub = InstrumentClient(channel,
    options: CallOptions(timeout: constDuration(seconds: 30)));

try {
    var readRequest = ReadStatusRequest(id: 1);
    var response = await stub.readStatus(readRequest);
    setState(() {
    _message = response.status;
    });
} catch (e) {
    setState(() {
    _message = e.toString();
    });
}
}

The method create a ClientChannel instance on localhost, which use the port 5280 (same as the one used by our server). It would then use the connect to our server using the InstrumentClient class generated by protoc compiler in the previous step. Do not forget to add the reference to the greet.pbgrpc.dart.

import'package:democlient/src/generated/greet.pbgrpc.dart';

We then create an instanace of the ReadStatusRequest data type and use the stub.ReadStatus method to send the request.

var response = await stub.readStatus(readRequest);

That’s all we would require to connect to the gRPC server using flutter. The complete source code used in this example can be accessed from my github here.

One thought on “Create a Flutter gRPC client

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s