Site icon Vinsguru

gRPC Web Example

Overview:

In this article, I would like to show you a gRPC Web Example for a browser application to talk to a backend gRPC server. We had already discussed enough of various gRPC API types in this blog. You can take a look at them if you are new.

gRPC Web:

As we might be already aware, gRPC is a RPC framework implementation from google for client-server application development. gRPC uses HTTP2 as network protocol and protocol-buffers to define the API and data models for the application interaction. Inter-Microservices communication using gRPC is very easy to implement. But what about browsers? Can they talk to the backend server using the proto files?

Yes, using gRPC Web, we could use the same proto file for the browser applications to interact with backend gRPC server to develop a full stack gRPC application.

 

Sample Application:

To keep things simple, I would like to re-use an existing application, we had developed earlier for the backend gRPC application. This is a simple a calculator-service which exposes a couple of simple APIs.

message Input {
  int32 number = 1;
}

message Output {
  int64 result = 1;
}

service CalculatorService {

  // unary
  rpc findSquare(Input) returns (Output);

  // server stream
  rpc findFactors(Input) returns (stream Output);

}

Our backend server is already developed which exposes the API. Now our browser/client-side application has to interact with this gRPC server to send the request and get the response. That is what we are going to discuss here.

Browsers HTTP2 Support:

Before we continue, we need to discuss the current limitations of browsers. Browsers do support HTTP2 to get the static files like images, javascript, css etc. But for any XMLHttpRequest/Ajax calls, browsers still use HTTP/1.1. It is a limitation of browsers as of now. Because of this limitation, browser / client side javascript can not directly talk to the backend gRPC server as we normally talk to the backend REST API. So, we need to work around this limitation and use envoy as a proxy. Envoy’s role here is to get the HTTP/1.1 requests from the browsers and convert to appropriate gRPC requests to the backend servers and respond to the client.

I am skipping the envoy configuration in this article. But it is available in GitHub. You can find the link at the end of this article.

gRPC Web – Client Side Application:

Let’s use the above proto file to develop our client side application. Our client should be able to send a request and receive the response. The response could be a simple request-response or streaming-response. In order to auto generate gRPC-client code, we need to have following binaries in our PATH variable. So download them and rename them with the following names and keep them in your local machine. Ensure that these binaries path are included in the system PATH variable.

To generate the client code, run the following command.

protoc --js_out=import_style=commonjs:output
       --grpc-web_out=import_style=commonjs,mode=grpcwebtext:output 
       calculator.proto

I am going to create a simple HTML using bootstrap to call the findSquare and findFactors APIs as shown here. The STOP button is to stop the streaming API when you do not want to receive any more responses for the request.

We need to bring grpc-web and google-protobuf modules to develop the frontend application. So you need to have npm installed in your machine. Create a project which contains package.json with the following dependencies.

{
  "name": "calculator-client",
  "version": "1.0.0",
  "description": "",
  "main": "client.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "google-protobuf": "^3.19.4",
    "grpc-web": "^1.3.1"
  }
}

Now we could develop our application by importing the above auto generated js files. Create client.js file with the following content.

const {Input, Output} = require('./calculator/calculator_pb.js');
const {CalculatorServiceClient} = require('./calculator/calculator_grpc_web_pb.js');

// here 8080 is envoy port
// envoy will forward to grpc server and respond to client
var client = new CalculatorServiceClient('http://localhost:8080');

gRPC Web Unary:

We have everything ready to call our backend gRPC server. In this case, when we click on the ‘Find‘ button for the Square Input, we would make the unary call.

const squareInput = document.getElementById('square-input');
const squareFind = document.getElementById('square-button');

squareFind.addEventListener('click', () => {
  var input = new Input();
  input.setNumber(squareInput.value);
  client.findSquare(input, {}, (err, r) => {
    addResponse(r);
  });
});

gRPC Web Streaming:

To make a server-streaming request, try as shown here.

const factorInput = document.getElementById('factor-input');
const factorFind = document.getElementById('factor-button');

factorFind.addEventListener('click', () => {
  var input = new Input();
  input.setNumber(factorInput.value);
  var stream = client.findFactors(input, {});
  stream.on('data', (r) => {
    addResponse(r);
  });
  stream.on('status', (status) => {
    console.log(status.code);
  });
  stream.on('end', (end) => {
    
  });
  document.getElementById('factor-stop').addEventListener('click', () => {
      stream.cancel();
  });
});

The addResponse method adds the response to the UI as bootstrap alert. Check GitHub for the complete code.

Once the client.js is ready, use module bundler like WebPack/BrowserifyFor ex: below command will bundle our client.js and their dependencies into bundle.js for HTML to include.

browserify src/client.js -o bundle.js
<script src="./bundle.js"></script>

Demo:

 

Summary:

We were able to successfully develop a simple gRPC Web application which can talk to the backend gRPC server. We were also able to make both unary and streaming calls. Using the gRPC Web Streaming we could receive updates from our backend server periodically.

The source code is available here.

Learn more on gRPC:

Share This:

Exit mobile version