82

We want to build a Javascript/HTML gui for our gRPC-microservices. Since gRPC is not supported on the browser side, we thought of using web-sockets to connect to a node.js server, which calls the target service via grpc. We struggle to find an elegant solution to do this. Especially, since we use gRPC streams to push events between our micro-services. It seems that we need a second RPC system, just to communicate between the front end and the node.js server. This seems to be a lot of overhead and additional code that must be maintained.

Does anyone have experience doing something like this or has an idea how this could be solved?

Oliver
  • 1,007
  • 1
  • 9
  • 10
  • Check out [Wildcard API](https://github.com/reframejs/wildcard-api) which is a small tool that allows you to easily create an RPC API between your frontend and your Node.js server. It's like gRPC but much simpler and much easier to use. Disclosure: I'm the author. – brillout Sep 04 '19 at 19:15

8 Answers8

43

Edit: Since Oct 23,2018 the gRPC-Web project is GA, which might be the most official/standardized way to solve your problem. (Even if it's already 2018 now... ;) )

From the GA-Blog: "gRPC-Web, just like gRPC, lets you define the service “contract” between client (web) and backend gRPC services using Protocol Buffers. The client can then be auto generated. [...]"

We recently built gRPC-Web (https://github.com/improbable-eng/grpc-web) - a browser client and server wrapper that follows the proposed gRPC-Web protocol. The example in that repo should provide a good starting point.

It requires either a standalone proxy or a wrapper for your gRPC server if you're using Golang. The proxy/wrapper modifies the response to package the trailers in the response body so that they can be read by the browser.

Disclosure: I'm a maintainer of the project.

Saphirim
  • 55
  • 9
Marcus
  • 778
  • 9
  • 20
  • 4
    killer feature would be now the ability to create a HTML playground page for any proto file similar to the one done for swagger. That way any gRPC service can be tested with via the browser easily. – Setheron Jan 03 '18 at 23:03
  • 1
    @Marcus, you say it follows the "Proposed gRPC-Web protocol". Is that the same protocol used by the official https://github.com/grpc/grpc-web implementation (that was recently made public) and would these implementations thus be compatible? Or are you referring to your own proposed protocol? – Matthijs Kooijman Apr 23 '18 at 14:38
  • @Setheron can you give me a link to example or description of this concreate killer feature? I can't find it yet :( I have gRPC-Web application (node.js) with binary (base64) messages and Envoy Proxy like at official docs, and I want to have swagger-like tool to test my app – razon Oct 24 '18 at 13:29
  • Can this project be connected with wordpress (php ) too ? – Jeff Bootsholz Mar 18 '19 at 03:54
17

Unfortunately, there isn't any good answer for you yet.

Supporting streaming RPCs from the browser fully requires HTTP2 trailers to be supported by the browsers, and at the time of the writing of this answer, they aren't.

See this issue for the discussion on the topic.

Otherwise, yes, you'd require a full translation system between WebSockets and gRPC. Maybe getting inspiration from grpc-gateway could be the start of such a project, but that's still a very long shot.

Nicolas Noble
  • 699
  • 3
  • 7
  • Thanks for your answer! I already read about the problem with the http trailers. There is even a patch that somebody did so that it is possible to use grpc in the browser without the streaming feature. The grpc-gateway project is a useful hint. We are probably doing a gateway with dnode now... – Oliver Feb 08 '16 at 15:51
  • 1
    Yes, if you forget about streaming, then grpc from the browser is totally possible. – Nicolas Noble Feb 20 '16 at 02:14
  • @NicolasNoble - that's great. Is there an example of a non-streaming gRPC call from a browser? – AlikElzin-kilaka Aug 01 '16 at 14:01
  • Not yet unfortunately. I was speaking theoretically. But the changes should be minimal. – Nicolas Noble Aug 16 '16 at 23:05
  • Any update to this with gRPC being released at version 1 and proto3? – Amitabh Aug 24 '16 at 14:52
  • 1
    We are collecting names of people interested in early access program [here](https://docs.google.com/forms/u/0/d/15iRDHoP-VBenc4hWgKn7bk7IirJLgs0uh88nw1vi_Hc/edit). Feel free to add your name in there and we'll share what we have Soon. – Nicolas Noble Aug 24 '16 at 23:44
  • Mentioned in my answer but I have a proxy that will transparently upgrade to websockets on top of grpc-gateway. – tmc Oct 14 '16 at 18:28
10

An official grpc-web (beta) implementation was released on 3/23/2018. You can find it at

https://github.com/grpc/grpc-web

The following instructions are taken from the README:

Define your gRPC service:

service EchoService {
  rpc Echo(EchoRequest) returns (EchoResponse);

  rpc ServerStreamingEcho(ServerStreamingEchoRequest)
      returns (stream ServerStreamingEchoResponse);
}

Build the server in whatever language you want.

Create your JS client to make calls from the browser:

var echoService = new proto.grpc.gateway.testing.EchoServiceClient(
  'http://localhost:8080');

Make a unary RPC call

var unaryRequest = new proto.grpc.gateway.testing.EchoRequest();
unaryRequest.setMessage(msg);
echoService.echo(unaryRequest, {},
  function(err, response) {
    console.log(response.getMessage());
  });

Streams from the server to the browser are supported:

var stream = echoService.serverStreamingEcho(streamRequest, {});
stream.on('data', function(response) {
  console.log(response.getMessage());
});

Bidirectional streams are NOT supported:

This is a work in progress and on the grpc-web roadmap. While there is an example protobuf showing bidi streaming, this comment make it clear that this example doesn't actually work yet.

Hopefully this will change soon. :)

Cody A. Ray
  • 5,869
  • 1
  • 37
  • 31
  • 1
    Are you sure bidirectional streams are supported? Your bidirectional example seems to show only server streaming, while your server streaming example only shows a unary request without any streaming. The README also mentions only server streaming, which makes me suspect client or bidirectional streaming is not supported. Could you clarify? – Matthijs Kooijman Apr 23 '18 at 14:43
  • 2
    @MatthijsKooijman Their echo example shows both client and full duplex streaming: https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/echo.proto#L96 – Cody A. Ray Apr 23 '18 at 14:52
  • 1
    it seems that that example is just for future reference, it is not actually supported. See also https://github.com/grpc/grpc-web/issues/24#issuecomment-303285538 which states this about the example explicitly. – Matthijs Kooijman Apr 24 '18 at 06:02
  • 1
    @MatthijsKooijman looks like you're right. I've updated my answer to reflect this (and included a link to the roadmap and the comment). Thanks! – Cody A. Ray Apr 25 '18 at 00:07
  • 1
    now you removed the streaming server example from your answer (which you previously had mis-labeled as bidirectional streaming). – Matthijs Kooijman Apr 25 '18 at 08:17
  • Interesting https://github.com/grpc/grpc-web/blob/01c9ac61b87279c0f592acbc6155760c1b63ee5e/net/grpc/gateway/examples/echo/echotest.html – Alex Punnen Jul 24 '18 at 05:28
7

https://github.com/tmc/grpc-websocket-proxy sounds like it may meet your needs. This translates json over web sockets to grpc (layer on top of grpc-gateway).

tmc
  • 716
  • 7
  • 15
7

The grpc people at https://github.com/grpc/ are currently building a js implementation.

The repro is at https://github.com/grpc/grpc-web (gives 404 ->) which is currently (2016-12-20) in early access so you need to request access.

RickyA
  • 15,465
  • 5
  • 71
  • 95
3

GRPC Bus WebSocket Proxy does exactly this by proxying all GRPC calls over a WebSocket connection to give you something that looks very similar to the Node GRPC API in the browser. Unlike GRPC-Gateway, it works with both streaming requests and streaming responses, as well as non-streaming calls.

There is both a server and client component. The GRPC Bus WebSocket Proxy server can be run with Docker by doing docker run gabrielgrant/grpc-bus-websocket-proxy

On the browser side, you'll need to install the GRPC Bus WebSocket Proxy client with npm install grpc-bus-websocket-client

and then create a new GBC object with: new GBC(<grpc-bus-websocket-proxy address>, <protofile-url>, <service map>)

For example:

var GBC = require("grpc-bus-websocket-client");

new GBC("ws://localhost:8080/", 'helloworld.proto', {helloworld: {Greeter: 'localhost:50051'}})
  .connect()
  .then(function(gbc) {
    gbc.services.helloworld.Greeter.sayHello({name: 'Gabriel'}, function(err, res){
      console.log(res);
    });  // --> Hello Gabriel
  });

The client library expects to be able to download the .proto file with an AJAX request. The service-map provides the URLs of the different services defined in your proto file as seen by the proxy server.

For more details, see the GRPC Bus WebSocket Proxy client README

Gabriel Grant
  • 5,415
  • 2
  • 32
  • 40
2

I see a lot of answers didn't point to a bidirectional solution over WebSocket, as the OP asked for browser support.

You may use JSON-RPC instead of gRPC, to get a bidirectional RPC over WebSocket, which supports a lot more, including WebRTC (browser to browser).

I guess it could be modified to support gRPC if you really need this type of serialization.

However, for browser tab to browser tab, request objects are not serializsed and are transfered natively, and the same with NodeJS cluster or thread workers, which offers a lot more performance.

Also, you can transfer "pointers" to SharedArrayBuffer, instead of serializing through the gRPC format.

JSON serialization and deserialization in V8 is also unbeatable.

https://github.com/bigstepinc/jsonrpc-bidirectional

oxygen
  • 5,891
  • 6
  • 37
  • 69
0

Looking at the current solutions with gRPC over web, here is what's available out there at the time of writing this (and what I found):

I also want to shamelessly plug my own solution which I wrote for my company and it's being used in production to proxy requests to a gRPC service that only includes unary and server streaming calls:

Every inch of the code is covered by tests. It's an Express middleware so it needs no additional modifications to your gRPC setup. You can also delegate HTTP authentication to Express (e.g with Passport).

Sepehr
  • 2,051
  • 19
  • 29
  • Hey! grpc-express looks cool, esp. for those using Express who don't need client streaming. I'm curious what additional tests you'd like for [gRPC-bus-websocket-proxy-server](https://github.com/gabrielgrant/grpc-bus-websocket-proxy-server)? It's a fairly thin wrapper/transport layer for grpc-bus (which is pretty well unit-tested), so I don't think it really makes sense to duplicate those, and the "demo" is effectively the acceptance test. In any case, we are actively using it in [Pachyderm](http://pachyderm.io), it just hasn't needed to be updated much recently because it mostly Just Works :) – Gabriel Grant Mar 15 '18 at 23:44