gRPC: Go Server & Web Client
Greeting
Hi everyone, my name is Bismo or sometimes they called me “Momo”. I am working as a Backend Engineer in Zeals. At Zeals, I am mostly taking care of RPA project microservices. This article is for the 25th day of Zeals Advent Calendar 2021. Please check out and find the other interesting story there!
Introduction
In this article, I want to share about the gRPC connection between the server (using Go) and the client (for Web). If you are not familiar with the gRPC concept, here is the official website that can help to understand gRPC: https://grpc.io/docs/what-is-grpc/introduction/
In gRPC, a client application can directly call a method on a server application on a different machine as if it were a local object, making it easier for you to create distributed applications and services.
Use Case
The common use case of gRPC implementation is mostly on the microservices-based application architecture communication. According to Ruan Fernando, gRPC connections are considerably faster (7–10 times) than using REST connections. IMO, this could be the reason why the communication between microservices is using gRPC. In my team (RPA) we also use gRPC for the connections.
Web-Clients
When the microservices use gRPC, how about communication between client apps (web, mobile) and server apps (microservices)? In consideration of that, it’s common to use an API gateway to wrap all RPC’s into REST API. Not only microservices that use gRPC, but also those using REST. To achieve this condition, either build API gateway by ourselves or use API gateway management like:
The previous background will be leading to another question, is it possible for client apps to access gRPC? The answer is let’s try it!
To give an instance, I will talk about the web platform. Because in Zeals we only have a web platform. There is a gRPC web library to generate for the client code:
Proto File
We need to build gRPC app, maybe just a simple app is fine. Because my background is Gopher :) we will use an example from this repository:
Copy the hello.proto
file to a structured project like this:
+ your_gopath/
|
+--+ src/github.com/moemoe89
| |
| +--+ grpc-web-example/
| |
| +--+ files
| |
| +--+ proto
| |
| +--+ hello.proto
|
+--+ bin/
| |
| +-- ... executable file
|
+--+ pkg/
|
+-- ... all dependency_library required
Generate Proto
To establish the connections between server and client, we need to generate the code based on proto files definition. In this tutorial, we will use buf as an ecosystem tool to generate multiple programming language codes with a single command. The detail of buf can be seen on the repository or the docs.
There are 2 files necessary in terms of generating the code.
- buf.yaml
- buf.gen.yaml
buf.yaml
can be generated by buf config init
the command. Then modify the file to have this config:
buf.gen.yaml
should be created manually. The config contains what the programming language needs to generate.
Considering we will generate Go and Web files, it’s necessary to install a generator for both plugins. The reference can be followed on these links:
- https://grpc.io/docs/languages/go/quickstart/#prerequisites
- https://github.com/grpc/grpc-web#code-generator-plugin
After the plugin is installed, easily run buf generate
the command to generate the files. The project structure will look like this:
+ your_gopath/
|
+--+ src/github.com/moemoe89
| |
| +--+ grpc-web-example/
| |
| +--+ files
| | |
| | +--+ go
| | | |
| | | +--+ hello.pb.go
| | | + hello_grpc.pb.go
| | |
| | +--+ proto
| | | |
| | | +--+ hello.proto
| | |
| | +--+ web
| | |
| | +--+ hello_pb.d.ts
| | + hello_pb.js
| | + HelloServiceClentPb.ts
| |
| +--+ buf.gen.yaml
| + buf.yaml
|
+--+ bin/
| |
| +-- ... executable file
|
+--+ pkg/
|
+-- ... all dependency_library required
Server App
Create a new directory in the same level with files, copy main.go
file and modify like this:
From the code above, we need to add a mechanism to run HTTP Server based on a wrapped gRPC Server. The gRPC Web client should call the HTTP Server instead of gRPC Server. Later, run go mod init
and go mod tidy
command in the root project. The structure will look like this:
+ your_gopath/
|
+--+ src/github.com/moemoe89
| |
| +--+ grpc-web-example/
| |
| +--+ files
| | |
| | +--+ go
| | | |
| | | +--+ hello.pb.go
| | | + hello_grpc.pb.go
| | |
| | +--+ proto
| | | |
| | | +--+ hello.proto
| | |
| | +--+ web
| | |
| | +--+ hello_pb.d.ts
| | + hello_pb.js
| | + HelloServiceClentPb.ts
| |
| +--+ server
| | |
| | +--+ main.go
| |
| +--+ buf.gen.yaml
| + buf.yaml
| + go.mod
| + go.sum
|
+--+ bin/
| |
| +-- ... executable file
|
+--+ pkg/
|
+-- ... all dependency_library required
Client App
Following the previous implementation, the next part is configuring the client-side. We will use Typescript to build the web. There are several files required, for the detail please check this link.
Anyway, the main 2 files to running the web are the index.html
and main.ts
.
index.html
will generate the UI and main.ts
has responsibility for the logic to call the wrapped gRPC server.
The final project structure will be formed like this:
+ your_gopath/
|
+--+ src/github.com/moemoe89
| |
| +--+ grpc-web-example/
| |
| +--+ client
| | |
| | +--+ static
| | |
| | +--+ index.html
| | + .gitignore
| | + main.ts
| | + package.json
| | + tsconfig.json
| | + webpack.config.js
| | + yarn.lock
| |
| +--+ files
| | |
| | +--+ go
| | | |
| | | +--+ hello.pb.go
| | | + hello_grpc.pb.go
| | |
| | +--+ proto
| | | |
| | | +--+ hello.proto
| | |
| | +--+ web
| | |
| | +--+ hello_pb.d.ts
| | + hello_pb.js
| | + HelloServiceClentPb.ts
| |
| +--+ server
| | |
| | +--+ main.go
| |
| +--+ buf.gen.yaml
| + buf.yaml
| + go.mod
| + go.sum
|
+--+ bin/
| |
| +-- ... executable file
|
+--+ pkg/
|
+-- ... all dependency_library required
Testing
After both server and client are ready, it’s time to test it! First of all, run the server with this command: go run ./server/main.go
from root project and wait until the server is ready.
$ go run ./server/main.go
$ 2021/12/25 21:12:25 grpc server listening at 127.0.0.1:50051
$ 2021/12/25 21:12:25 http server listening at localhost:50052
Better to validate the server working well by calling the RPC using GUI. We will use Postman because since v9.7.0 they support gRPC requests!! Although still on Beta.
Using gRPC in Postman is quite simple, just fill the URL, import the proto file, and make a call! Please follow the page to install the app.
As the result above, there’s no issue when calling SayHello
. It’s mean the server is working well!! How about the client?
Go to client
directory, run the commandyarn install
, yarn build
(if not yet) and yarn start
to start the client app.
$ yarn start
yarn run v1.22.11
warning package.json: No license field
warning ../../../../../../package.json: No license field
$ webpack && http-server ./static
Hash: ce32c2d7136c8d0f91fd
Version: webpack 4.46.0
Time: 1399ms
Built at: 12/20/2021 9:51:26 PM
Asset Size Chunks Chunk Names
bundle.js 344 KiB main [emitted] main
Entrypoint main = bundle.js
[../files/web/HelloServiceClientPb.ts] 1.44 KiB {main} [built]
[../files/web/hello_pb.js] 9.45 KiB {main} [built]
[./main.ts] 1020 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
+ 6 hidden modules
Starting up http-server, serving ./static
Available on:
http://127.0.0.1:8080
http://192.168.1.6:8080
Hit CTRL-C to stop the server
Open http://127.0.0.1:8080 on the browser, fill the form and click Send. See what happens…
Yoooppp!! The gRPC Web successfully called the server and got the response!!
Conclusion
Wrapping up the previous section, implementing the gRPC Web for client is possible. But isn’t simple compared to some common programming languages for Backend (in my experience e.g. Golang, Ruby, Python).
Because if the gRPC Web client wants to communicate with gRPC server, we need to modify the server to wrap the gRPC server into an HTTP server.
When I am looking for another implementation, although I am not trying it yet, using Envoy proxy sounds cool because don’t need to make any changes on the server-side. Maybe we can have another experiment for Envoy proxy? Let’s see it :)
But yeah, the gRPC Web is still interesting to me, maybe in the future, there will be an update (?), who knows. I hope this article is useful for you, any comment & feedback are welcome, thank you!!
If you need the full source code for this experiment, please visit my repository here: