✔️ Design a gRPC service
✔️ Write a protocol buffer file
✔️ Make gRPC unary call
✔️ Implement a gRPC server
✔️ Implement a gRPC client
What you will do and why:
Let's say that you need to implement a way of communicating between a client and a server. You've probably heard of the REST model, one of the way that you can implement which is very common in web development. During this workshop, you will implement a communication channel between a client and a server using gRPC, which is one of the other ways to communicate - like REST does.
But what is gRPC ?
- gRPC stands for google Remote Procedure Call.
- It is a framework developed by Google on top of the RPC protocol.
- When dealing with gRPC, the data sent between the client and the server is packed in a specific format: protobuffers.
💡 Okay, but why do we use protobuf and not JSON ? JSON are nice: they are human-readable, easy to build and to extract. In fact, it is the data serialization method used in a lot of REST APIs.
But why gRPC instead of REST ?
- gRPC's communication speed is faster than REST one
- gRPC is kinda easier to implement, but not faster
- gRPC uses HTTP/2, which is better than HTTP 1.1, the one that REST uses
You can learn more about the main differences between these two models on this great blog post. I highly recommend that you take a look at the article, it is easy to understand, and you will learn a lot of stuff !
Please follow the instructions available here.
When dealing with gRPC, you need to define two things in a very specific file: the protobuf file. These two things are :
Service
- This is the global communication between two entitiesMessage
- It defines the messages sent and received during the communication
-
Create a folder
messenger
-
In this folder, create a
messenger.proto
file -
Create a
MessengerService
in themessenger.proto
file -
This service has a
Send
rpc, which:- Takes a
Content
message as an argument - Returns a
Content
message
- Takes a
-
Well now, create the
Content
message, which contains:- A string, named
body
- An int, named
date
- A string, named
-
The package name of this protobuf file must be
messenger
-
The syntax version you must use is
proto3
-
Don't forget to set the
option go_package
with the value./
Run the following command and nothing should have appeared on your screen:
protoc --go_out=messenger --go-grpc_out=messenger messenger/messenger.proto
Two files were generated in the
messenger
directory, we'll use them later 😉
Before implementing both the server and the client, you will implement the main logic of the program, which will:
- Take several arguments
- Start as the server or the client
-
Create a
main.go
file at the root of your working folder -
Create a
main
function -
Check the first argument provided to the program
- If it is
-s
, it will start the server. For the moment, just printStarting the server
- If it is
-c
, it will start the client. For the moment, just printStarting the client
- Otherwise, the program will exit with an error code of 1
- If it is
Run the following commands:
go run main.go "-s"
go run main.go "-c"
Should print respectively:
go run main.go "-s"
Starting the server
go run main.go "-c"
Starting the client
And running the following command:
go run main.go "-h"
Should print:
exit status 1
At the first step, the protoc compiler generated 2 files: messenger_grpc.pb.go
and messenger.pb.go
.
Let's focus on the first one, which contains a lot of things, including a MessengerServiceServer
interface.
During this step, you will implement this interface and its method, Send
.
-
Open the
messenger/messenger_grpc.pb.go
file -
Look for the
MessengerServiceServer
-
Create a folder named
server
at the root of your working directory -
Create a
server.go
file in theserver
folder -
In the
server/server.go
file, create aServer
structure which contains nothing for the moment -
Create a
Send
method for theServer
structure which takes the same arguments as theSend
method of theMessengerServiceServer
interface- Print the content received with the following format:
[SERVER]: received {body} at {date}
- Return the following message to the client:
hello from server !
with the current date as a UNIX timestamp
- Print the content received with the following format:
Now that your Server
structure implements all the MessengerServiceServer
methods, you can start the server.
- Add a field named
listener
in theServer
structure - Add a field named
core
in theServer
structure - Embed the unimplemented server in the
Server
structure - Add a
New
method to theServer
structure- The core is a
grpc.Server
that you must create using a method from the grpc package - You must register the server using one of the method in
messenger_grpc.pb.go
- Then return the instance of the created
Server
- The core is a
Let's start the server:
- Add a
Start
method to theServer
structure - Use the
core
and thelistener
property to start serving.
In the main.go
file:
- Below the print of
Starting the server
, create a new server and start it- The listener must listen on
tcp:9000
- The listener must listen on
- Look at the generated protobuf file :)
Run the following command:
go run main.go -s
Should make the program run indefinitely !
Your server is running, but you need a way to send request. Here comes the client !
During this step, you will create a client and add methods allowing it to connect, send a message and disconnect from the server.
-
Create a folder named
client
-
In this folder, create a
client.go
file -
In this file, create a
Client
structure -
Create a
New
function, which creates a newClient
instance -
The
New
function initialize two members of the structureconn
which is agrpc.ClientConn
core
which is your messenger's client- The connection can be insecure for now
-
Create a
Disconnect
method, which closes the client connection -
Create a
Send
method, which sends the message given as parameter. It returns the response received from the server
In the main.go
file:
- Below the print of
Starting the client
, create a new client and send a message
- Look at the protobuf generated file :)
- Run the server
go run main.go -s
- Open a new terminal, and run
go run main.go -c
The server should print:
$ go run main.go -s
Starting the server
[SERVER]: received Hello World! at 1659805496
The timestamp is obviously different in your case.
When you don't need the server to run anymore, or whenever the client has stopped sending their requests, we need to shut it down properly.
As you created the Disconnect
method for the client, you only need to create the same method for the server that
triggers whenever you hit CTRL + C
.
- Capture when the user hit
CTRL + C
on the server-side - Create a
Stop
method for the server and call it when necessary - Use the
Disconnect
method for the client when it has sent its message
Try to hit CTRL + C
while running the server, and it should shut down without any error message.
For the moment, you are using an int to represent the date, but there is the Timestamp type available in protobuf.
Take a look at the gRPC streams and try to implement a stream RPC in the current project.
Or you can try to write the client in another programming language ! Here comes the power of protobuf :)
You can add more services to the protobuf file, passing other type of parameters instead of a string, or even combining more data types.
If you want to learn more about gRPC project out there, check out this list of amazing projects that uses it.
Luca Georges Francois |
---|
🚀 Don't hesitate to follow us on our different networks, and put a star 🌟 on
PoC's
repositories.