A simple demo: The basics of gRPC using a Flutter client and a Rust server

Matthäus Pordzik
4 min readMay 27, 2022

--

Photo by Joanna Kosinska on Unsplash

gRPC (general-purpose Remote Procedure Calls) is a framework developed by Google, based on the RPC protocol, for calling functions in distributed systems. It has some advantages that result from using HTTP/2 as its transfer protocol. gRPC can be seen as an alternative to popular data query and manipulation languages such as REST or GraphQL.

This article is intended to be a simple introduction demo to enable anyone to kick-start gRPC in their next project and focuses on the core concepts of the protocol and does not cover more advanced topics such us load balancing, call cancelation or interceptors.

The examples given in this article are based on a Flutter client and a Rust server in order to show a basic implementation with a popular frontend/backend combination.

gRPC Packages

The basic structure of a gRPC package is based on a definition of messages and services. gRPC packages are associated with .proto files which must be known to the client and the server in order to correctly handle and serialise messages. These messages are defined using protocol buffers and support various data types and structures. Services consist of RPCs which are basically some remote function definitions based on messages.

In summary, services allow four types of RPCs:

  1. A simple unary RPC where the client sends a single request to the server and gets a single response back
  2. A server-side streaming RPC where the client sends a single request to the server and gets a stream of data back
  3. A client-side streaming RPC where the client sends a stream of data to the server and gets a single response back
  4. A bidirectional streaming RPC where both sides send streams of data independently.

In this article, we will focus on the first three types of service methods and how they work.

A simple package

In gRPC, the client triggers communication. For this reason, it usually make sense to define service and message names from the client’s point of view. The following file shows the simple package my_grpc_service with two messages MyGrpcRequest and MyGrpcResponse and an associated service MyGrpcService. The service consists of three different types of RPCs.

This file will be used to generate gRPC code for the client and the server. The official gRPC website gives an overview of some popular libraries that are used for this purpose. The basis of these libraries usually consists of the protoc compiler.

A basic implementation

Prerequisites

For Flutter, the packages grpc and protobuf have to be added. For Rust, the popular crates tonic and tokio are used. Furthermore the protoc compiler has to be installed and added to PATH.

Generate gRPC code

It is common practice to put .proto files into a top level folder called protos. For this reason, the .proto file is placed there for both projects.

The dart code can be generated by running the following command in the terminal:

This will generate all dart files that are needed to implement the service and will place them in lib/generated.

The Rust code can be generated using a build script. The build script build.rs is placed next to the .toml file and defines operations to be performed before the build process. In this scenario the build script consists of the following lines:

This will generate all Rust files that are needed to implement the service and place them in the build folder.

After that the generated dart client MyGrpcServiceClient has to be packed into a service. This gives the possibility to inject the service via Providers into various parts of the Flutter app. On the server side, the generated trait MyGrpcService has to be implemented in order to give the service some functionality.

Simple unary RPCs

In the case of a simple unary RPCs, a function is defined that receives some request message and returns some response message.

In the case of a simple unary RPCs, a function is defined as well that receives some request message and returns some response message.

Server-side streaming RPCs

In the case of server-side streaming RPCs the client gets a stream of response messages. These messages can be fetched asynchronously and then passed on to the Flutter app via another stream which can be listened to.

On the server side some iterable data is created and channels are spawned using tokio. These channels transmit single response messages by queing the items.

Client-side streaming RPCs

In the case of client-side streaming RPCs the client sends a stream of request messages and receives a single response message. The input for this service function is a stream that is provided by the Flutter app.

On the server side request messages are fetched and iterated over. After that a single response message is send back to the client.

Repositories with demos

  1. Flutter gRPC client demo
  2. Rust gRPC server demo

Wrapping it up

This article should have given a quick and simple introduction to the gRPC framework and has shown a basic implementation of simple unary, server-side streaming and client-side streaming RPCs. It should be clear what kind of data is received and sent by the server and the client during each RPC and what the core concepts are.

--

--