Top Related Projects
gRPC for Web Clients
gRPC to JSON proxy generator following the gRPC HTTP spec
A simple RPC framework with protobuf service definitions
The TypeScript implementation of Connect: Protobuf RPC that works.
Quick Overview
The improbable-eng/grpc-web
project is a set of client and server libraries that enable the use of gRPC in web applications. It allows developers to build modern, efficient, and type-safe web applications by leveraging the power of gRPC, a high-performance remote procedure call (RPC) framework.
Pros
- Cross-Platform Compatibility: The project supports multiple programming languages, including JavaScript, TypeScript, Go, and more, making it accessible to a wide range of developers.
- Efficient Data Transfer: gRPC's binary protocol and efficient serialization techniques enable faster data transfer compared to traditional REST APIs.
- Type Safety: The project integrates with TypeScript, providing type-safe communication between the client and server, reducing the risk of errors.
- Scalability: gRPC's asynchronous and streaming capabilities make it well-suited for building scalable and responsive web applications.
Cons
- Complexity: Integrating gRPC-Web into a web application may require more setup and configuration compared to traditional REST APIs, which can be a barrier for some developers.
- Browser Compatibility: While gRPC-Web aims to provide a seamless experience, there may be some browser compatibility issues that need to be addressed, especially for older browsers.
- Learning Curve: Developers new to gRPC may need to invest time in understanding the concepts and best practices of the framework, which can slow down initial development.
- Limited Tooling: The gRPC-Web ecosystem may have fewer tools and libraries compared to more established web development frameworks, which can make it harder to find pre-built solutions.
Code Examples
Here are a few code examples demonstrating the usage of the improbable-eng/grpc-web
project:
- Defining a gRPC Service in Protocol Buffers:
syntax = "proto3";
package example;
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
- Generating Client Code in TypeScript:
import * as grpcWeb from 'grpc-web';
import { HelloServiceClient } from './example_grpc_web_pb';
import { HelloRequest, HelloResponse } from './example_pb';
const client = new HelloServiceClient('http://localhost:8080');
const request = new HelloRequest();
request.setName('John');
client.sayHello(request, (err: grpcWeb.Error, response: HelloResponse) => {
if (err) {
console.error(err);
} else {
console.log(response.getMessage());
}
});
- Implementing a gRPC-Web Server in Go:
package main
import (
"log"
"net/http"
"github.com/improbable-eng/grpc-web/go/grpcweb"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
pb "example/proto"
)
type helloServer struct{}
func (s *helloServer) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
return &pb.HelloResponse{Message: "Hello, " + req.Name}, nil
}
func main() {
grpcServer := grpc.NewServer()
pb.RegisterHelloServiceServer(grpcServer, &helloServer{})
reflection.Register(grpcServer)
wrappedGrpc := grpcweb.WrapServer(grpcServer)
http.Handle("/", wrappedGrpc)
log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Getting Started
To get started with the improbable-eng/grpc-web
project, follow these steps:
- Install the necessary dependencies:
- For the client-side, install the
grpc-web
package using your preferred package manager (e.g., `npm
- For the client-side, install the
Competitor Comparisons
gRPC for Web Clients
Pros of grpc-web
- Official implementation by the gRPC team, ensuring better long-term support and compatibility
- Supports more gRPC features, including streaming and interceptors
- Better integration with existing gRPC ecosystems and tools
Cons of grpc-web
- Requires a proxy server for browser compatibility, adding complexity to deployment
- Less flexible in terms of browser support, mainly focusing on modern browsers
- Steeper learning curve for developers new to gRPC concepts
Code Comparison
grpc-web:
const { HelloRequest } = require('./helloworld_pb.js');
const { GreeterClient } = require('./helloworld_grpc_web_pb.js');
const client = new GreeterClient('http://localhost:8080');
const request = new HelloRequest();
request.setName('World');
client.sayHello(request, {}, (err, response) => {
console.log(response.getMessage());
});
improbable-eng/grpc-web:
import { grpc } from "@improbable-eng/grpc-web";
import { HelloRequest, HelloReply } from "./helloworld_pb";
import { Greeter } from "./helloworld_pb_service";
const client = grpc.client(Greeter.SayHello, {
host: "http://localhost:8080",
});
client.start();
client.send(new HelloRequest().setName("World"));
client.onMessage((message: HelloReply) => {
console.log(message.getMessage());
});
Both implementations achieve similar results, but grpc-web uses a more traditional callback approach, while improbable-eng/grpc-web offers a more modern, Promise-based API.
gRPC to JSON proxy generator following the gRPC HTTP spec
Pros of grpc-gateway
- Generates RESTful JSON API from gRPC service definitions
- Supports both gRPC and REST API endpoints simultaneously
- Integrates well with existing HTTP/REST infrastructure
Cons of grpc-gateway
- Requires additional setup and configuration
- May introduce performance overhead due to translation layer
- Limited support for streaming operations compared to native gRPC
Code Comparison
grpc-gateway:
import (
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
)
mux := runtime.NewServeMux()
err := pb.RegisterYourServiceHandlerFromEndpoint(ctx, mux, grpcServerEndpoint, opts)
grpc-web:
import { grpc } from "@improbable-eng/grpc-web";
const client = grpc.client(YourService.YourMethod, {
host: "https://example.com",
});
client.start();
grpc-gateway acts as a reverse proxy, translating RESTful JSON requests to gRPC calls, while grpc-web enables direct gRPC communication from web browsers. grpc-gateway offers better integration with existing REST ecosystems, whereas grpc-web provides a more native gRPC experience for web clients.
A simple RPC framework with protobuf service definitions
Pros of Twirp
- Simpler and more lightweight than gRPC-Web
- Easier to set up and use, with less configuration required
- Supports both JSON and Protobuf encoding out of the box
Cons of Twirp
- Less feature-rich compared to gRPC-Web
- Limited to HTTP/1.1, doesn't support HTTP/2 or streaming
- Smaller community and ecosystem
Code Comparison
Twirp:
service Haberdasher {
rpc MakeHat(Size) returns (Hat);
}
gRPC-Web:
const client = new HaberdasherClient('http://localhost:8080');
const request = new Size();
request.setInches(10);
client.makeHat(request, {}, (err, response) => {
// Handle response
});
Both projects aim to simplify communication between clients and servers using Protocol Buffers. Twirp focuses on simplicity and ease of use, making it a good choice for smaller projects or those new to RPC. gRPC-Web offers more advanced features and better performance, but with increased complexity. The choice between them depends on the specific needs of your project, such as required features, performance requirements, and development team expertise.
The TypeScript implementation of Connect: Protobuf RPC that works.
Pros of Connect
- Simplicity: Connect is a lightweight and easy-to-use RPC framework, making it a good choice for simple use cases.
- Flexibility: Connect supports multiple transport protocols, including HTTP, WebSocket, and gRPC, allowing it to be used in a variety of scenarios.
- Typescript Support: Connect is written in Typescript, providing type safety and better tooling support.
Cons of Connect
- Limited Features: Compared to gRPC-Web, Connect may lack some advanced features and functionality, such as streaming, bidirectional communication, and comprehensive service definitions.
- Smaller Community: gRPC-Web has a larger and more active community, with more resources and support available.
- Performance: gRPC-Web is generally considered to have better performance characteristics than Connect, especially for large-scale or high-throughput applications.
Code Comparison
Here's a brief code comparison between Connect and gRPC-Web:
Connect (client-side):
import { createClient } from 'connect-es';
const client = createClient('http://example.com/rpc');
const response = await client.invoke('myMethod', { arg1: 'value' });
console.log(response);
gRPC-Web (client-side):
import { HelloClient } from './hello_grpc_web_pb.js';
import { HelloRequest } from './hello_pb.js';
const client = new HelloClient('http://example.com');
const request = new HelloRequest();
request.setName('John');
client.sayHello(request, {}, (err, response) => {
console.log(response.getMessage());
});
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
gRPC-Web: Typed Frontend Development
Please note that this repo is in maintenance mode, and we recommend users migrate to the official grpc-web client: https://github.com/grpc/grpc-web.
gRPC is a modern, HTTP2-based protocol, that provides RPC semantics using the strongly-typed binary data format of protocol buffers across multiple languages (C++, C#, Golang, Java, Python, NodeJS, ObjectiveC, etc.)
gRPC-Web is a cutting-edge spec that enables invoking gRPC services from modern browsers.
If you are looking for gRPC support for Node.js there is an official Node.js gRPC library. This package supports Node.js, but requires that the server has the gRPC-Web compatibility layer (read on to understand more).
Components of the stack are based on Golang and TypeScript:
grpcweb
- a Go package that wraps an existinggrpc.Server
as a gRPC-Webhttp.Handler
for both HTTP2 and HTTP/1.1.grpcwebproxy
- a Go-based stand-alone reverse proxy for classic gRPC servers (e.g. in Java or C++) that exposes their services over gRPC-Web to modern browsers.ts-protoc-gen
- a TypeScript plugin for the protocol buffers compiler that provides strongly typed message classes and method definitions.@improbable-eng/grpc-web
- a TypeScript gRPC-Web client library for browsers (and Node.js).
Why?
With gRPC-Web, it is extremely easy to build well-defined, easy to reason about APIs between browser frontend code and microservices. Frontend development changes significantly:
- no more hunting down API documentation -
.proto
is the canonical format for API contracts. - no more hand-crafted JSON call objects - all requests and responses are strongly typed and code-generated, with hints available in the IDE.
- no more dealing with methods, headers, body and low level networking - everything is handled by
grpc.invoke
. - no more second-guessing the meaning of error codes - gRPC status codes are a canonical way of representing issues in APIs.
- no more one-off server-side request handlers to avoid concurrent connections - gRPC-Web is based on HTTP2, with multiplexes multiple streams over the same connection.
- no more problems streaming data from a server - gRPC-Web supports both 1:1 RPCs and 1:many streaming requests.
- no more data parse errors when rolling out new binaries - backwards and forwards-compatibility of requests and responses.
In short, gRPC-Web moves the interaction between frontend code and microservices from the sphere of hand-crafted HTTP requests to well-defined user-logic methods.
Client-side (grpc-web) Docs
Note: You'll need to add gRPC-Web compatibility to your server through either grpcweb
or grpcwebproxy
.
API Docs for grpc-web
client can be found here
Example
For a self-contained demo of a Golang gRPC service called from a TypeScript project, see example. It contains most of the initialization code that performs the magic. Here's the application code extracted from the example:
You use .proto
files to define your service. In this example, one normal RPC (GetBook
) and one server-streaming RPC (QueryBooks
):
syntax = "proto3";
message Book {
int64 isbn = 1;
string title = 2;
string author = 3;
}
message GetBookRequest {
int64 isbn = 1;
}
message QueryBooksRequest {
string author_prefix = 1;
}
service BookService {
rpc GetBook(GetBookRequest) returns (Book) {}
rpc QueryBooks(QueryBooksRequest) returns (stream Book) {}
}
And implement it in Go (or any other gRPC-supported language):
import pb_library "../_proto/examplecom/library"
type bookService struct{
books []*pb_library.Book
}
func (s *bookService) GetBook(ctx context.Context, bookQuery *pb_library.GetBookRequest) (*pb_library.Book, error) {
for _, book := range s.books {
if book.Isbn == bookQuery.Isbn {
return book, nil
}
}
return nil, grpc.Errorf(codes.NotFound, "Book could not be found")
}
func (s *bookService) QueryBooks(bookQuery *pb_library.QueryBooksRequest, stream pb_library.BookService_QueryBooksServer) error {
for _, book := range s.books {
if strings.HasPrefix(s.book.Author, bookQuery.AuthorPrefix) {
stream.Send(book)
}
}
return nil
}
You will be able to access it in a browser using TypeScript (and equally JavaScript after transpiling):
import {grpc} from "@improbable-eng/grpc-web";
// Import code-generated data structures.
import {BookService} from "../_proto/examplecom/library/book_service_pb_service";
import {QueryBooksRequest, Book, GetBookRequest} from "../_proto/examplecom/library/book_service_pb";
const queryBooksRequest = new QueryBooksRequest();
queryBooksRequest.setAuthorPrefix("Geor");
grpc.invoke(BookService.QueryBooks, {
request: queryBooksRequest,
host: "https://example.com",
onMessage: (message: Book) => {
console.log("got book: ", message.toObject());
},
onEnd: (code: grpc.Code, msg: string | undefined, trailers: grpc.Metadata) => {
if (code == grpc.Code.OK) {
console.log("all ok")
} else {
console.log("hit an error", code, msg, trailers);
}
}
});
Usage with React
Browser Support
The @improbable-eng/grpc-web
client uses multiple techniques to efficiently invoke gRPC services. Most modern browsers support the Fetch API, which allows for efficient reading of partial, binary responses. For older browsers, it automatically falls back to XMLHttpRequest
.
The gRPC semantics encourage you to make multiple requests at once. With most modern browsers supporting HTTP2, these can be executed over a single TLS connection. For older browsers, gRPC-Web falls back to HTTP/1.1 chunk responses.
This library is tested against:
- Chrome >= 41
- Firefox >= 38
- Edge >= 13
- IE >= 11
- Safari >= 8
Node.js Support
The @improbable-eng/grpc-web
client also supports Node.js through a transport that uses the http
and https
packages. Usage does not vary from browser usage as transport is determined at runtime.
If you want to use the @improbable-eng/grpc-web
client in a node.js environment with Typescript, you must include dom
in the "lib"
Array in your tsconfig.json
otherwise tsc
will be unable to find some type declarations to compile. Note that dom
will be included automatically if you do not declare lib
in your configration and your target is one of es5
or es6
. (See Typescript compiler options).
{
"compilerOptions": {
"lib": [ "dom", /* ... */ ],
}
}
Please note - There is an official Node.js gRPC library that does not require the server to support gRPC-Web
Client-side streaming
It is very important to note that the gRPC-Web spec currently does not support client-side streaming. This is unlikely to change until new whatwg fetch/streams API lands in browsers. As such, if you plan on using gRPC-Web you're limited to:
- unary RPCs (1 request 1 response)
- server-side streaming RPCs (1 request N responses)
This, however, is useful for a lot of frontend functionality.
Note that @improbable-eng/grpc-web
provides a built-in websocket transport that can support client-side/bi-directional streaming RPCs.
Status
The code here is alpha
quality. It is being used for a subset of Improbable's frontend single-page apps in production.
Known Limitations
See the @improbable-eng/grpc-web
client Transport Documentation for a list of Web Browser caveats.
Contributing
See CONTRIBUTING
Top Related Projects
gRPC for Web Clients
gRPC to JSON proxy generator following the gRPC HTTP spec
A simple RPC framework with protobuf service definitions
The TypeScript implementation of Connect: Protobuf RPC that works.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot