gRPC: Go Server & Web Client

Bismo Baruno
The Zeals Tech Blog
8 min readDec 24, 2021
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!

Zeals Advent Calendar 2021

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.

gRPC Client-Server communication. Picture by grpc.io

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:

API Gateway Architecture

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:

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.

Testing gRPC server using Postman

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…

Testing from client-side

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:

--

--