- Notifications
You must be signed in to change notification settings - Fork793
grpc/grpc-web
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A JavaScript implementation ofgRPC for browser clients. For more information,including aquick start, see thegRPC-web documentation.
gRPC-web clients connect to gRPC services via a special proxy; by default,gRPC-web usesEnvoy.
In the future, we expect gRPC-web to be supported in language-specific webframeworks for languages such as Python, Java, and Node. For details, see theroadmap.
gRPC-web currently supports 2 RPC modes:
- Unary RPCs (example)
- Server-side Streaming RPCs (example) (NOTE: Only when
grpcwebtextmode is used.)
Client-side and Bi-directional streaming is not currently supported (seestreaming roadmap).
Eager to get started? Try theHello World example. From this example, you'lllearn how to do the following:
- Define your service using protocol buffers
- Implement a simple gRPC Service using Node.js
- Configure the Envoy proxy
- Generate protobuf message classes and client service stub for the client
- Compile all the JS dependencies into a static library that can be consumedby the browser easily
You can also try to run a more advanced Echo app from the browser with astreaming example.
From the repo root directory:
$ docker-compose pull prereqs node-server envoy commonjs-client$ docker-compose up node-server envoy commonjs-client
Open a browser tab, and visithttp://localhost:8081/echotest.html.
To shutdown:docker-compose down.
The gRPC-web runtime library is available on npm:
$ npm i grpc-web
If you don't already haveprotocinstalled, download it first fromhere and install it on your PATH.
If you use Homebrew (on macOS), you could run:
brew install protobuf
If you don't haveprotoc-gen-js installed, download it fromprotocolbuffers/protobuf-javascript and install it on your PATH.
Or, use thethird-party npm installer:
npm install -g protoc-gen-jsYou can download theprotoc-gen-grpc-web protoc plugin from ourrelease page:
Make sure all executables are discoverable from your PATH.
For example, on macOS, you can do:
sudo mv protoc-gen-grpc-web-2.0.2-darwin-aarch64 \ /usr/local/bin/protoc-gen-grpc-webchmod +x /usr/local/bin/protoc-gen-grpc-web
Note: If you are using our Docker setup, theprereqs image already includesbothprotoc and theprotoc-gen-grpc-web plugin on the PATH.
You can optionally verify the plugins work by following ourHello World example:
cd net/grpc/gateway/examples/helloworldprotoc -I=. helloworld.proto \ --js_out=import_style=commonjs:. \ --grpc-web_out=import_style=commonjs,mode=grpcwebtext:.After the command runs successfully, you should now see two new files generatedin the current directory. By running:
ls -1 *_pb.jsInstallation is successful if you see the following 2 files:
helloworld_pb.js— Generated byprotoc-gen-jspluginhelloworld_grpc_web_pb.js- Generated by gRPC-Web plugin
Typically, you will run the following command to generate the proto messagesand the service client stub from your.proto definitions:
protoc -I=$DIR echo.proto \ --js_out=import_style=commonjs:$OUT_DIR \ --grpc-web_out=import_style=commonjs,mode=grpcwebtext:$OUT_DIR
You can then use Browserify, Webpack, Closure Compiler, etc. to resolve importsat compile time.
import_style=closure: The default generated code hasClosuregoog.require()import style.
import_style=commonjs: TheCommonJS stylerequire() isalso supported.
import_style=commonjs+dts: (Experimental) In addition to above, a.d.tstypings file will also be generated for the protobuf messages and service stub.
import_style=typescript: (Experimental) The service stub will be generatedin TypeScript. SeeTypeScript Support below for information on how togenerate TypeScript files.
Note: The
commonjs+dtsandtypescriptstyles are only supported by--grpc-web_out=import_style=..., not by--js_out=import_style=....
For more information about the gRPC-web wire format, see thespecification.
mode=grpcwebtext: The default generated code sends the payloads in thegrpc-web-text format.
Content-Type: application/grpc-web-text- Payloads are base64-encoded.
- Both unary and server streaming calls are supported.
mode=grpcweb: A binary protobuf format is also supported.
Content-Type: application/grpc-web+proto- Payloads are in the binary protobuf format.
- Only unary calls are supported.
Let's take a look at how gRPC-web works with a simple example. You can find outhow to build, run and explore the example yourself inBuild and Run the Echo Example.
The first step when creating any gRPC service is to define it. Like all gRPCservices, gRPC-web usesprotocol buffers to defineits RPC service methods and their message request and response types.
messageEchoRequest {stringmessage=1;}...serviceEchoService {rpcEcho(EchoRequest)returns (EchoResponse);rpcServerStreamingEcho(ServerStreamingEchoRequest)returns (streamServerStreamingEchoResponse);}
Next you need to have a gRPC server that implements the service interface and agateway proxy that allows the client to connect to the server. Our examplebuilds a simple Node gRPC backend server and the Envoy proxy.
For the Echo service: see theservice implementation.
For the Envoy proxy: see theconfig YAML file.
Once the server and gateway are up and running, you can start making gRPC callsfrom the browser!
Create your client:
varechoService=newproto.mypackage.EchoServiceClient('http://localhost:8080');
varrequest=newproto.mypackage.EchoRequest();request.setMessage(msg);varmetadata={'custom-header-1':'value1'};echoService.echo(request,metadata,function(err,response){if(err){console.log(err.code);console.log(err.message);}else{console.log(response.getMessage());}});
varstream=echoService.serverStreamingEcho(streamRequest,metadata);stream.on('data',function(response){console.log(response.getMessage());});stream.on('status',function(status){console.log(status.code);console.log(status.details);console.log(status.metadata);});stream.on('end',function(end){// stream end signal});// to close the streamstream.cancel();
For an in-depth tutorial, seethispage.
You can set a deadline for your RPC by setting adeadline header. The valueshould be a Unix timestamp, in milliseconds.
vardeadline=newDate();deadline.setSeconds(deadline.getSeconds()+1);client.sayHelloAfterDelay(request,{deadline:deadline.getTime().toString()},(err,response)=>{// err will be populated if the RPC exceeds the deadline ...});
Thegrpc-web module can now be imported as a TypeScript module. This iscurrently an experimental feature. Any feedback welcome!
When using theprotoc-gen-grpc-web protoc plugin, mentioned above, pass ineither:
import_style=commonjs+dts: existing CommonJS style stub +.d.tstypingsimport_style=typescript: full TypeScript output
Donot useimport_style=typescript for--js_out, it will silently beignored. Instead you should use--js_out=import_style=commonjs, or--js_out=import_style=commonjs,binary if you are usingmode=grpcweb. The--js_out plugin will generate JavaScript code (echo_pb.js), and the-grpc-web_out plugin will generate a TypeScript definition file for it(echo_pb.d.ts). This is a temporary hack until the--js_out supportsTypeScript itself.
For example, this is the command you should use to generate TypeScript codeusing the binary wire format:
protoc -I=$DIR echo.proto \ --js_out=import_style=commonjs,binary:$OUT_DIR \ --grpc-web_out=import_style=typescript,mode=grpcweb:$OUT_DIR
It will generate the following files:
EchoServiceClientPb.ts- Generated by--grpc-web_out, contains theTypeScript gRPC-web code.echo_pb.js- Generated by--js_out, contains the JavaScript Protobufcode.echo_pb.d.ts- Generated by--grpc-web_out, contains TypeScriptdefinitions forecho_pb.js.
import*asgrpcWebfrom'grpc-web';import{EchoServiceClient}from'./EchoServiceClientPb';import{EchoRequest,EchoResponse}from'./echo_pb';constechoService=newEchoServiceClient('http://localhost:8080',null,null);constrequest=newEchoRequest();request.setMessage('Hello World!');constcall=echoService.echo(request,{'custom-header-1':'value1'},(err:grpcWeb.RpcError,response:EchoResponse)=>{console.log(response.getMessage());});call.on('status',(status:grpcWeb.Status)=>{// ...});
(Seehere for the full list of possible.on(...) callbacks.)
NOTE: It is not possible to access the
.on(...)callbacks (e.g. formetadataandstatus) when Promise is used.
// Create a Promise client insteadconstechoService=newEchoServicePromiseClient('http://localhost:8080',null,null);...(sameasabove)this.echoService.echo(request,{'custom-header-1':'value1'}).then((response:EchoResponse)=>{console.log(`Received response:${response.getMessage()}`);}).catch((err:grpcWeb.RpcError)=>{console.log(`Received error:${err.code},${err.message}`);});
For the full TypeScript example, seets-example/client.ts and theinstructions to run.
Custom interceptors can be implemented and chained, which could be useful for features like auth, retries, etc.
There are 2 types of interceptors (interfaces):
UnaryInterceptor(doc,example) - Intercept Unary RPCs; can only be used with Promise clients.StreamInterceptor(doc,example) - More versatile; can be used with regular clients.
For more details, seethis blog post.
Multiple proxies support the gRPC-web protocol.
The currentdefault proxy isEnvoy, which supports gRPC-web out of the box.
$ docker-compose up -d node-server envoy commonjs-client
You can also try thegRPC-web Go Proxy.
$ docker-compose up -d node-server grpcwebproxy binary-client
ApacheAPISIX has also added gRPC-web support, and more details can be foundhere.
Nginx has a gRPC-web module (doc,announcement)), and seems to work with simple configs, according to userfeedback.
About
gRPC for Web Clients
Topics
Resources
License
Code of conduct
Contributing
Security policy
Uh oh!
There was an error while loading.Please reload this page.