Build client-server application using gRPC
A quick help on how to create and execute a simple client-server application using gRPC
Introduction
gRPC is a an open source RPC (Remote Procedure Call) framework that can be used to create high performance distributed applications and services. If you would like to have an introduction to gRPC, refer to my earlier article here, which gives a brief introduction to gRPC, it’s features and suitable usecases.
In this article, we’ll cover how to create and execute a simple client-server application using gRPC.
Target Audience
This article is intended for those who are relatively new to gRPC, but, may have some experience with Go programming language. If you are already familiar with gRPC, well, feel free to glance through. :-)
What are we building?
To keep things simple, let’s go with a very basic example: a service to search whether a product is in stock or not. Needless to say, we’ll focus only on the gRPC aspects of it and leave out rest of the logic as future scope. In short, nothing fancy :-)
We’ll define the service, create both server and client version of the application using Go programming language.
Prerequisites
Go
Since we are planning to use Go, ensure that Go programming language installed and configured in your machine. If not done already, no worries; Feel free to refer my earlier article which explains step by step on how to setup up local development environment.
Protocol Buffers
Another prerequisite we have is Protocol Buffers (version 3 i.e. proto3). To configure the same, download pre-compiled binary from here. You could choose a binary which is relevant for your platform: (e.g.: protoc-3.17.0-linux-x86_64.zip)
Unzip the file and keep it in a relevant directory. You would be able to see the compiler file (protoc) in the directory. Include the same in PATH.
Run the following to see if the configuration is correct.
protoc version
You should be able to see something similar:
Go plugins
In addition to Protocol Buffers compiler, we also need to install the following Go plugins
$ go install google.golang.org/protobuf/cmd/protoc-gen-go
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
Above statements will install the Go plugins to GOPATH/bin location. Ensure that GOPATH/bin is added to PATH variable.
On a Linux machine, you could do it as follows:
$ $export PATH=”$PATH:$(go env GOPATH)/bin”
Project Structure
Now, let’s look at how to structure our project.
Our project will have a service definition, it’s supporting files, implementation files for client & server and, a main file to start the program. (In ideal case, the client implementation would be kept separate from server implementation. To keep things simple, we’ll keep all relevant parts in the same project itself.)
When completed, our project structure would look like the following.
Now, let’s create a Go project (say grpc_go_example) with modules enabled. Create directories to keep client, server and service definition as shown above.
Service Definition
Fundamental building block for gRPC is the service definition. Let’s start with defining our service as follows.
Let’s try to understand what these statements mean.
First line in the file is to specify which version of Protocol Buffers we would use, followed by go package details. Next, a service is defined along with message structure for both request and response. Save the file as product.proto in protof directory.
Now, we need to compile the .proto file to generate it’s supporting files.
Execute the following from the project directory
$ protoc — go_out=. — go_opt=paths=source_relative — go-grpc_out=. — go-grpc_opt=paths=source_relative protof/product.proto
After executing this, you would be able to see two additional files (product_grpc.pb.go and product.pb.go) generated in the protof directory. We’ll use these files to implement both server and client programs.
Server Implementation
It’s time to implement the server now.
Import and declaration
First, let’s define the package and import a few required packages. Note that, we need to import the package where our service definition files are kept as well. Let’s also specify a port to use.
Server Implementation
Next step is to implement the server. To do so, let’s define a struct called server and implement protof.ProductServer interface (present in product_grpc.pb.go file). We’ll add a simple response logic in Search() method as indicated.
Server Entry point
Now, let’s add an entry point as follows, which would be used by main function, to invoke server.
Now, the server implementation is ready.
Client Implementation
Let’s proceed to implement client.
Import and declaration
Similar to server implementation, let’s define the package, import necessary packages and define the address. To simplify, we’ll also add a constant for default product.
Client entry point
Next step is to add an entry point as follows, which would be used by main function, to invoke client.
Now, we are done with client implementation.
Main Program
Now, it’s time to create the final piece in the puzzle, the main program.
Import
Here, we’ll keep the package as main and import both client and server packages.
Entry point
In the main function, we’ll expect an argument (client or server) and accordingly, respective function would be called as follows.
Execution
Now, it’s time to run the program.
Scenario 1
To execute the server and client, run the commands as shown below, in sequence in two different terminals.
As you can see above, server has responded back with the result.
Since we did not specify any product, client send the default product we specified.
Scenario 2
Let’s try running the client with another product as an argument, in another terminal.
Since this product is not configured, server responds back with “not in stock” message.
Source Code
If you would like to experiment, working version of the program can be found in the following GitHub repo:
That’s all for now.
Thank you reading so far. Till we meet next time, happy coding!