grpc.io/public/blog/grpc-web-ga/index.html

256 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/css/style.css">
<title>
gRPC-Web is Generally Available &ndash; gRPC
</title>
<link rel="apple-touch-icon" href="/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" type="image/png" href="/favicons/android-chrome-192x192.png" sizes="192x192" >
<link rel="icon" type="image/png" href="/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/favicons/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/favicons/manifest.json">
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#2DA6B0">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/favicons/mstile-150x150.png">
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-60127042-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-60127042-1');
</script>
</head>
<body>
<div id="landing-content">
<div class="row">
<div class="topbannersub">
<nav class="navbar navbar-expand-md navbar-dark topnav">
<a class="navbar-brand" href="https://cjyabraham.github.io/">
<img src="https://cjyabraham.github.io/img/grpc-logo.png" width="114" height="50">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="topnav, collapse navbar-collapse" id="navbarSupportedContent" style="float:right !important">
<ul class="navbar-nav ml-auto">
<li class="nav-item ">
<a class="nav-link" href="https://cjyabraham.github.io/about/">About</a>
</li>
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle" href="https://cjyabraham.github.io/docs/" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Docs
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="/docs">
Overview
</a>
<a class="dropdown-item" href="/docs/quickstart/">
Quick Start
</a>
<a class="dropdown-item" href="/docs/guides/">
Guides
</a>
<a class="dropdown-item" href="/docs/tutorials/">
Tutorials
</a>
<a class="dropdown-item" href="/docs/reference/">
Reference
</a>
<a class="dropdown-item" href="/docs/samples/">
Samples
</a>
<a class="dropdown-item" href="/docs/talks">
Presentations
</a>
</div>
</li>
<li class="nav-item active">
<a class="nav-link" href="/blog">
Blog
</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="/community">Community</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://packages.grpc.io/">
Packages
</a>
</li>
<li class="nav-item ">
<a class="nav-link" href="https://cjyabraham.github.io/faq/">FAQ</a>
</li>
</ul>
</div>
</nav>
<div class="headertext">Blog</div>
</div>
</div>
</div>
<div class="singleblog">
<h1>gRPC-Web is Generally Available</h1>
<h5>Posted on Tuesday, October 23, 2018
by
Luc Perkins - CNCF, Stanley Cheung - Google, Kailash Sethuraman - Google
</h5>
<p>
<p>We are excited to announce the GA release of
<a href="https://www.npmjs.com/package/grpc-web">gRPC-Web</a>, a JavaScript client library
that enables web apps to communicate directly with gRPC backend services,
without requiring an HTTP server to act as an intermediary. &ldquo;GA&rdquo; means that
gRPC-Web is now Generally Available and stable and qualified for production use.</p>
<p>With gRPC-Web, you can now easily build truly end-to-end gRPC application
architectures by defining your client <em>and</em> server-side data types and service
interfaces with Protocol Buffers. This has been a hotly requested feature for a
while, and we are finally happy to say that it is now ready for production use.
In addition, being able to access gRPC services opens up new an exciting
possibilities for <a href="https://github.com/grpc/grpc-experiments/tree/master/gdebug">web based
tooling</a> around gRPC.</p>
<h2 id="the-basics">The Basics</h2>
<p>gRPC-Web, just like gRPC, lets you define the service &ldquo;contract&rdquo; between client
(web) and backend gRPC services using Protocol Buffers. The client can then be
auto generated. To do this, you have a choice between the <a href="https://developers.google.com/closure/compiler/">Closure</a> compiler
or the more widely used <a href="https://requirejs.org/docs/commonjs.html">CommonJS</a>.
This development process removes the need to manage concerns such as creating
custom JSON seralization and deserialization logic, wrangling HTTP status codes
(which can vary across REST APIs), managing content type negotiation etc.</p>
<p>From a broader architectural perspective, gRPC-Web enables end-to-end gRPC. The diagram below illustrates this:</p>
<p><img src="/img/grpc-web-arch.png" style="max-width: 947px"></p>
<p style="text-align: center"> Figure 1.
gRPC with gRPC-Web (left) and gRPC with REST (right)</p>
<p>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.</p>
<h2 id="advantages-of-using-grpc-web">Advantages of using gRPC-Web</h2>
<p>gRPC-Web will offer an ever-broader feature set over time, but heres whats in 1.0 today:</p>
<ul>
<li><strong>End-to-end gRPC</strong> — Enables 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. Theres a good chance that youll spend as much time building the HTTP interaction layer as you will building the entire rest of the pipeline.</li>
<li><strong>Tighter coordination between frontend and backend teams</strong> — 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.</li>
<li><strong>Easily generate client libraries</strong> — 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 services 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.</li>
</ul>
<h2 id="a-grpc-web-example">A gRPC-Web example</h2>
<p>The previous section illustrated some of the high-level advantages of gRPC-Web for large-scale applications. Now lets get closer to the metal with an example: a simple TODO app. In gRPC-Web you can start with a simple <code>todos.proto</code> definition like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-proto" data-lang="proto">syntax <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;proto3&#34;</span>;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#f92672">package</span> todos;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">message</span> <span style="color:#a6e22e">Todo</span> {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">string</span> content <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">bool</span> finished <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span>;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span>}<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">message</span> <span style="color:#a6e22e">GetTodoRequest</span> {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">int32</span> id <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span>}<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">service</span> TodoService {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">rpc</span> GetTodoById (GetTodoRequest) <span style="color:#66d9ef">returns</span> (Todo);<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span>} </code></pre></div>
<p>CommonJS client-side code can be generated from this <code>.proto</code> definition with the following command:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-proto" data-lang="proto">protoc echo.proto <span style="color:#960050;background-color:#1e0010">\
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#f92672">--</span>js_out<span style="color:#f92672">=</span>import_style<span style="color:#f92672">=</span>commonjs<span style="color:#f92672">:./</span>output <span style="color:#960050;background-color:#1e0010">\
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#f92672">--</span>grpc<span style="color:#f92672">-</span>web_out<span style="color:#f92672">=</span>import_style<span style="color:#f92672">=</span>commonjs<span style="color:#f92672">:./</span>output</code></pre></div>
<p>Now, fetching a list of TODOs from a backend gRPC service is as simple as:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-js" data-lang="js"><span style="color:#66d9ef">const</span> {<span style="color:#a6e22e">GetTodoRequest</span>} <span style="color:#f92672">=</span> <span style="color:#a6e22e">require</span>(<span style="color:#e6db74">&#39;./todos_pb.js&#39;</span>);
<span style="color:#66d9ef">const</span> {<span style="color:#a6e22e">TodoServiceClient</span>} <span style="color:#f92672">=</span> <span style="color:#a6e22e">require</span>(<span style="color:#e6db74">&#39;./todos_grpc_web_pb.js&#39;</span>);
<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">todoService</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">proto</span>.<span style="color:#a6e22e">todos</span>.<span style="color:#a6e22e">TodoServiceClient</span>(<span style="color:#e6db74">&#39;http://localhost:8080&#39;</span>);
<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">todoId</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">1234</span>;
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">getTodoRequest</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">proto</span>.<span style="color:#a6e22e">todos</span>.<span style="color:#a6e22e">GetTodoRequest</span>();
<span style="color:#a6e22e">getTodoRequest</span>.<span style="color:#a6e22e">setId</span>(<span style="color:#a6e22e">todoId</span>);
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">metadata</span> <span style="color:#f92672">=</span> {};
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">getTodo</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">todoService</span>.<span style="color:#a6e22e">getTodoById</span>(<span style="color:#a6e22e">getTodoRequest</span>, <span style="color:#a6e22e">metadata</span>, (<span style="color:#a6e22e">err</span>, <span style="color:#a6e22e">response</span>) =&gt; {
<span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">err</span>) {
<span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#a6e22e">err</span>);
} <span style="color:#66d9ef">else</span> {
<span style="color:#66d9ef">const</span> <span style="color:#a6e22e">todo</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">response</span>.<span style="color:#a6e22e">todo</span>();
<span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">todo</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span>) {
<span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">`A TODO with the ID </span><span style="color:#e6db74">${</span><span style="color:#a6e22e">todoId</span><span style="color:#e6db74">}</span><span style="color:#e6db74"> wasn&#39;t found`</span>);
} <span style="color:#66d9ef">else</span> {
<span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">`Fetched TODO with ID </span><span style="color:#e6db74">${</span><span style="color:#a6e22e">todoId</span><span style="color:#e6db74">}</span><span style="color:#e6db74">: </span><span style="color:#e6db74">${</span><span style="color:#a6e22e">todo</span>.<span style="color:#a6e22e">content</span>()<span style="color:#e6db74">}</span><span style="color:#e6db74">`</span>);
}
}
});
</code></pre></div>
<p>Once you declare the data types and a service interface, gRPC-Web abstracts away all the boilerplate, leaving you with a clean and human-friendly API (essentially the same API as the current <a href="/docs/tutorials/basic/node/">Node.js</a> for gRPC API, just transferred to the client).</p>
<p>On the backend, the gRPC server can be written in any language that supports gRPC, such as Go, Java, C++, Ruby, Node.js, and many others. The last piece of the puzzle is the service proxy. From the get-go, gRPC-Web will support <a href="https://envoyproxy.io">Envoy</a> as the default service proxy, which has a built-in <a href="https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/grpc_web_filter#config-http-filters-grpc-web">envoy.grpc_web filter</a> that you can apply with just a few lines of copy-and-pastable configuration.</p>
<h2 id="next-steps">Next Steps</h2>
<p>Going GA means that the core building blocks are firmly in place and ready for usage in production web applications. But theres still much more to come for gRPC-Web. Check out the <a href="https://github.com/grpc/grpc-web/blob/master/ROADMAP.md">official roadmap</a> to see what the core team envisions for the near future.</p>
<p>If youre interested in contributing to gRPC-Web, there are a few things we would love community help with:</p>
<ul>
<li><p><strong>Front-end framework integration</strong> — Commonly used front-end frameworks like <a href="https://reactjs.org">React</a>, <a href="https://vuejs.org">Vue</a> and <a href="https://angularjs.org">Angular</a> don&rsquo;t yet offer official support for gRPC-Web. But we would love to see these frameworks support it since the integration between these frontend frameworks and gRPC-Web can be a vehicle to deliver user-perceivable performance benefits to applications. If you are interested in building out support for these frontend frameworks, let us know on the <a href="https://groups.google.com/forum/#!forum/grpc-io">gRPC.io mailing list</a>, <a href="https://github.com/grpc/grpc-web/issues">filing a feature request on github</a> or via the feature survey form below.</p></li>
<li><p><strong>Language-specific proxy support</strong> — As of the GA release, <a href="https://envoyproxy.io">Envoy</a> is the default proxy for gRPC-Web, offering support via a special module. NGNIX is also <a href="https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/nginx">supported</a>. But wed also love to see development of in-process proxies for specific languages since they obviate the need for special proxies—such as Envoy and nginx—and would make using gRPC-Web even easier.</p></li>
</ul>
<p>Wed also love to get feature requests from the community. Currently the best way to make feature requests is to fill out the <a href="https://docs.google.com/forms/d/1NjWpyRviohn5jaPntosBHXRXZYkh_Ffi4GxJZFibylM/viewform?edit_requested=true">gRPC-Web roadmap features survey</a>. When filling up the form, list features youd like to see and also let us know if youd like to contribute to the development of those features in the <strong>Id like to contribute to</strong> section. The gRPC-Web engineers will be sure to take that information to heart over the course of the projects development.</p>
<p>Most importantly, we want to thank all the Alpha and Beta users who have given us feedback, bug reports and pull requests contributions over the course of the past year. We would certainly hope to maintain this momentum and make sure this project brings tangible benefits to the developer community.</p>
</p>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body>
</html>