On behalf of the Cloud Native Computing Foundation, I’m excited to announce the GA release of gRPC-Web, a JavaScript client library that enables web apps to communicate directly with backend gRPC services, without requiring an HTTP server to act as an intermediary. This means that you now easily build truly end-to-end gRPC application architectures by defining your client- and server-side data types and service interfaces using .proto files. gRPC-Web thus provides a compelling new alternative to the entire REST paradigm of web development.
The basics
gRPC-Web enables you to define the service “contract” between client web applications and backend gRPC servers using .proto definitions and auto-generate client JavaScript (you can choose between Closure compiler JavaScript or the more widely used CommonJS). What you get to leave out of the development process: creating custom JSON serialization and deserialization logic, wrangling HTTP status codes (which can vary across REST APIs), content type negotiation, etc.
From a broader architectural perspective, what gRPC-Web makes possible is end-to-end gRPC. The diagram below illustrates this:
In the gRPC-Web universe on the left, a client application speaks Protocol Buffers to a gRPC backend server that speaks Protocol Buffers to other gRPC backend services. In the REST universe on the right, the web app speaks HTTP to a backend REST API server that then speaks Protocol Buffers to backend services.
To be clear, there’s nothing wrong with the REST application on the right per se. Tons of highly successful applications have been built using REST API servers that communicate with backend services using non-HTTP protocols. But imagine those applications’ development processes united around a single protocol and a single set of .proto interfaces (and thus a single set of service contracts) and you can almost feel the countless hours saved and headaches avoided. The benefits of gRPC-Web aren’t “merely” technological; they’re organizational as well. That bright orange line isn’t just a different protocol—it’s an independent source of work and cognitive load that you can now easily turn bright green.
Advantages of using gRPC-Web
gRPC-Web will offer an ever-broader feature set over time. But I can see it offering a handful of big wins from the get-go:
- End-to-end gRPC — As mentioned above, with gRPC-Web you can officially cut the REST component out of your stack and replace it with pure gRPC, enabling you to craft your entire RPC pipeline using Protocol Buffers. Imagine a scenario in which a client request goes to an HTTP server, which then interacts with 5 backend gRPC services. There’s a good chance that you’ll spend as much time building the HTTP interaction layer as you will building the entire rest of the pipeline.
- Tighter coordination between frontend and backend teams — Think back to the diagram up above. With the entire RPC pipeline defined using Protocol Buffers, you no longer need to have your “microservices teams” alongside your “client team.” The client-backend interaction is just one more gRPC layer amongst others. I honestly have yet to fully grasp the implications for end-to-end testing, service mesh integration, continuous integration/delivery, and more.
- Easily generate client libraries — With gRPC-Web, the server that interacts with the “outside” world, i.e. the membrane connecting your backend stack to the internet, is now a gRPC server instead of an HTTP server, that means that all of your service’s client libraries can be gRPC libraries. Need client libraries for Ruby, Python, Java, and 4 other languages? You no longer need to write HTTP clients for all of them.
A gRPC-Web example
The previous section illustrated some of the high-level advantages of gRPC-Web for large-scale applications. Now let’s get closer to the metal with an example: a simple TODO app. In gRPC-Web you can start with a simple todos.proto definition like this:
syntax = “proto3”; | |
package todos; | |
message Todo { | |
string content = 1; | |
bool finished = 2; | |
} | |
message GetTodoRequest { | |
int32 id = 1; | |
} | |
service TodoService { | |
rpc GetTodoById (GetTodoRequest) returns (Todo); | |
} |
You can use that .proto definition to generate CommonJS client-side code using the protoc command-line tool:
protoc echo.proto \ | |
–js_out=import_style=commonjs:./output \ | |
–grpc-web_out=import_style=commonjs:./output |
Now fetching a list of TODOs from a backend gRPC server can be as simple as this:
const {GetTodoRequest} = require(‘./todos_pb.js’); | |
const {TodoServiceClient} = require(‘./todos_grpc_web_pb.js’); | |
const todoService = new proto.todos.TodoServiceClient(‘http://localhost:8080’); | |
const todoId = 1234; | |
var getTodoRequest = new proto.todos.GetTodoRequest(); | |
getTodoRequest.setId(todoId); | |
var metadata = {}; | |
var getTodo = todoService.getTodoById(getTodoRequest, metadata, (err, response) => { | |
if (err) { | |
console.log(err); | |
} else { | |
const todo = response.todo(); | |
if (todo == null) { | |
console.log(`A TODO with the ID ${todoId} wasn’t found`); | |
} else { | |
console.log(`Fetched TODO with ID ${todoId}: ${todo.content()}`); | |
} | |
} | |
}); |
Again, no HTTP codes or methods, no JSON parsing, no header negotiation. You declare data types and a service interface and gRPC-Web abstracts away all the “hard wiring” boilerplate, leaving you with a clean and human-friendly API (essentially the same API as the current Node.js for gRPC API, just transferred to the client).
On the backend, the gRPC server can be written in any language that supports gRPC, including Go, Java, C++, Ruby, Node.js, and many others (see language-specific docs in the official gRPC docs). The last piece of the puzzle is the service proxy. From the get-go, gRPC-Web will support Envoy as the default service proxy, which has a built-in envoy.grpc_web filter that you can apply with just a few lines of copy-and-pastable configuration. I’ll be saying more about this on the Envoy blog soon.
Next steps
Going GA means that the core building blocks are firmly in place and ready for usage in production web applications. But there’s still much more to come for gRPC-Web. Check out the official roadmap to see what the core team envisions for the near future.
If you’re interested in contributing to gRPC-Web, there are a few things that the core team would love community help with:
- Front-end framework integration — Commonly used front-end frameworks like React, Angular, and Vue don’t yet offer official support for gRPC-Web. But we would love to see these frameworks support it, as each of them would greatly benefit from gRPC.
- Language-specific proxy support — As of the GA release, Envoy is the default proxy for gRPC-Web, offering support via a special module. But we’d also love to see development of in-process proxies for specific languages. In-process proxies obviate the need for special proxies—such as Envoy and nginx—and would make using gRPC-Web even easier.
We’d also love to get feature requests from the community. Currently the best way to make feature requests is to fill out the gRPC-Web roadmap features survey. Just list features you’d like to see and also let us know if you’d like to contributing to those features’ development in the I’d like to contribute to section. The gRPC-Web engineers will be sure to take that information to heart over the course of the project’s development.