grpc-web — Using gRPC in your front end application

Konstantin Ostrovsky
3 min readJan 22, 2021

--

At StackPulse we use gRPC as our one and only synchronous communication protocol. Microservices communicate one with other using gRPC, our external api is exposed via gRPC and also our frontend application (that is written using VueJS) uses the gRPC protocol to communicate with our backend services.

One of the main strengths of gRPC is the community and the different languages support. Given some proto files you can generate a server and a client for most programming languages.

In this article, I will explain how to use communicate with your gRPC backend using the great grpc-web OSS project.

A quick reminder of our architecture

As you may remember from my previous blog posts we, at StackPulse, are using microservice architecture. Initially each microservice had an external and internal api endpoint.

After a working that way for several months we have realized that it doesn’t work as well as we’ve imagined. We’ve then decided to adopt the API Gateway/Backend For Frontend approach.

Current StackPulse architecture

I will publish a different blog post about this change in the future, however the main pain point was data consolidation across several microservices. The dreaded JOINs over gRPC.

gRPC Web

A JavaScript implementation of gRPC for browser clients. Unfortunately, it doesn’t use the native binary gRPC protocol to communicate with gRPC endpoints. It requires a special proxy that can translate requests from grpc-web into gRPC.

Envoy has built in support for this type of proxy.

Here is an example of the grpc-web proxy implementation in Golang. We use a similar one at StackPulse.

Building gRPC-Web clients

We generate gRPC clients for all our external APIs during the CI process. In case of gRPC-Web client an npm package is generated and it is published to github package repository.

A JavaScript application that wants to consume it will do it usingnpm install command.

Build example for one of our services

Sample client/server example

Our proto interface

Its a really simple service. You sent it GetCurrentTimeRequest and you get GetCurrentTimeResponse which contains the textual representation of time.Now().String() .

Generating clients and servers

In order to generate the clients and the servers for this proto file you need to use the protoc command. Generating grpc-web client and JavaScript definitions requires protoc-gen-grpc-web plugin. You can get it here or like me use the pre-baked docker image jfbrandhorst/grpc-web-generators that contains all the tools needed to work with grpc-web.

This is the command I’m using to generate both the Go clients/servers and the JavaScript clients:

docker run \
-v `pwd`/api:/api \
-v `pwd`/time/goclient:/goclient \
-v `pwd`/frontend/src/jsclient:/jsclient \
jfbrandhorst/grpc-web-generators \
protoc -I /api \
--go_out=plugins=grpc,paths=source_relative:/goclient \
--js_out=import_style=commonjs:/jsclient \
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:/jsclient \
/api/time/v1/time_service.proto

It will put the Go clients in ./time/goclient and the JavaScript clients in ./frontend/src/jsclient

Backend

A really basic Go server which just listens on 0.0.0.0:8080. It implements the TimeServiceServer interfaceand returns time.Now().String() for each request.

gRPC server implementation in Go

Frontend

Using grpc-web in frontend is pretty simple.

JavaScript client usage

This is pretty straight forward. I recommend enabling the grpc-web chrome extension support. It’s a great way to debug your traffic. You can find more details on the extension here.

Envoy configuration

Like I previously mentioned, grpc-web needs a proxy to translate into gRPC. Envoy has native support for this.

The following configuration example for Envoy does exactly that.

envoy grpc-web proxy configuration

Final words

I hope this article will help you easily dive into grpc-web. It’s great technology, especially if you are already using gRPC everywhere.

We are using this with great success in our frontend application.

You can find the source code for this article here.

--

--

Konstantin Ostrovsky

I used to write kernel drivers in C. Now I write Backend in Go :)