grpc.io/public/docs/tutorials/basic/web/index.html

343 lines
20 KiB
HTML

<!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 Basics - Web &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 active">
<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 ">
<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">Documentation</div>
</div>
</div>
</div>
<div class="subnav d-none d-md-block">
<a href="https://cjyabraham.github.io/docs/" >Overview</a>
| <a href="https://cjyabraham.github.io/docs/quickstart/" >Quick Start</a>
| <a href="https://cjyabraham.github.io/docs/guides/" >Guides</a>
| <a href="https://cjyabraham.github.io/docs/tutorials/" class="active">Tutorials</a>
| <a href="https://cjyabraham.github.io/docs/reference/" >Reference</a>
| <a href="https://cjyabraham.github.io/docs/samples/" >Samples</a>
| <a href="https://cjyabraham.github.io/docs/talks/" >Presentations</a>
</div>
<div class="quickstartcols">
<div class="quickstartcol1">
<h8>Tutorials</h8>
<a href="https://cjyabraham.github.io/docs/tutorials/async/helloasync-cpp/" >Async - C++</a>
<a href="https://cjyabraham.github.io/docs/tutorials/auth/oauth2-objective-c/" >Auth - Objective C</a>
<h8>Basic</h8>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/c/" >C++</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/csharp/" >C#</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/dart/" >Dart</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/go/" >Go</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/java/" >Java</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/android/" >Android Java</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/node/" >Node</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/objective-c/" >Objective-C</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/php/" >PHP</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/python/" >Python</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/ruby/" >Ruby</a>
<a href="https://cjyabraham.github.io/docs/tutorials/basic/web/" class="active">Web</a>
</div>
<div class="quickstartcol2" style="margin-top:4%">
<h3 style="margin-top:0px;">gRPC Basics - Web</h3>
<p>This tutorial provides a basic introduction on how to use
gRPC-Web from browsers.</p>
<p>By walking through this example you&rsquo;ll learn how to:</p>
<ul>
<li>Define a service in a .proto file.</li>
<li>Generate client code using the protocol buffer compiler.</li>
<li>Use the gRPC-Web API to write a simple client for your service.</li>
</ul>
<p>It assumes a passing familiarity with <a href="https://developers.google.com/protocol-buffers/docs/overview">protocol
buffers</a>.</p>
<div id="toc"></div>
<p><a name="why-grpc"></a></p>
<h3 id="why-use-grpc-and-grpc-web">Why use gRPC and gRPC-Web?</h3>
<p>With gRPC you can define your service once in a .proto file and implement
clients and servers in any of gRPC&rsquo;s supported languages, which in turn can be
run in environments ranging from servers inside Google to your own tablet - all
the complexity of communication between different languages and environments is
handled for you by gRPC. You also get all the advantages of working with
protocol buffers, including efficient serialization, a simple IDL, and easy
interface updating. gRPC-Web lets you access gRPC services built in this manner
from browsers using an idiomatic API.</p>
<p><a name="setup"></a></p>
<h3 id="define-the-service">Define the Service</h3>
<p>The first step when creating a gRPC service is to define the service methods
and their request and response message types using protocol buffers. In this
example, we define our <code>EchoService</code> in a file called
<a href="https://github.com/grpc/grpc-web/blob/0.4.0/net/grpc/gateway/examples/echo/echo.proto"><code>echo.proto</code></a>.
For more information about protocol buffers and proto3 syntax, please see the
<a href="https://developers.google.com/protocol-buffers/">protobuf documentation</a>.</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-protobuf" data-lang="protobuf"><span style="color:#66d9ef">message</span> <span style="color:#a6e22e">EchoRequest</span> {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">string</span> <span style="color:#66d9ef">message</span> <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">message</span> <span style="color:#a6e22e">EchoResponse</span> {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">string</span> <span style="color:#66d9ef">message</span> <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> EchoService {<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#66d9ef">rpc</span> Echo(EchoRequest) <span style="color:#66d9ef">returns</span> (EchoResponse);<span style="color:#960050;background-color:#1e0010">
</span><span style="color:#960050;background-color:#1e0010"></span>}</code></pre></div>
<h3 id="implement-grpc-backend-server">Implement gRPC Backend Server</h3>
<p>Next, we implement our EchoService interface using Node in the backend gRPC
<code>EchoServer</code>. This will handle requests from clients. See the file
<a href="https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/node-server/server.js"><code>node-server/server.js</code></a>
for details.</p>
<p>You can implement the server in any language supported by gRPC. Please see
the <a href="/docs/">main page</a> for more details.</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">function</span> <span style="color:#a6e22e">doEcho</span>(<span style="color:#a6e22e">call</span>, <span style="color:#a6e22e">callback</span>) {
<span style="color:#a6e22e">callback</span>(<span style="color:#66d9ef">null</span>, {<span style="color:#a6e22e">message</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">call</span>.<span style="color:#a6e22e">request</span>.<span style="color:#a6e22e">message</span>});
}
</code></pre></div>
<h3 id="configure-the-envoy-proxy">Configure the Envoy Proxy</h3>
<p>In this example, we will use the <a href="https://www.envoyproxy.io/">Envoy</a>
proxy to forward the gRPC browser request to the backend server. You can see
the complete config file in
<a href="https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/envoy.yaml">envoy.yaml</a></p>
<p>To forward the gRPC requests to the backend server, we need a block 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-yaml" data-lang="yaml"> listeners:
- name: listener_0
address:
socket_address: { address: <span style="color:#ae81ff">0.0</span>.<span style="color:#ae81ff">0.0</span>, port_value: <span style="color:#ae81ff">8080</span> }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: [<span style="color:#e6db74">&#34;*&#34;</span>]
routes:
- match: { prefix: <span style="color:#e6db74">&#34;/&#34;</span> }
route: { cluster: echo_service }
http_filters:
- name: envoy.grpc_web
- name: envoy.router
clusters:
- name: echo_service
connect_timeout: <span style="color:#ae81ff">0.</span>25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts: [{ socket_address: { address: node-server, port_value: <span style="color:#ae81ff">9090</span> }}]</code></pre></div>
<p>You may also need to add some CORS setup to make sure the browser can request
cross-origin content.</p>
<p>In this simple example, the browser makes gRPC requests to port <code>:8080</code>. Envoy
forwards the request to the backend gRPC server listening on port <code>:9090</code>.</p>
<h3 id="generate-protobuf-messages-and-service-client-stub">Generate Protobuf Messages and Service Client Stub</h3>
<p>To generate the protobuf message classes from our <code>echo.proto</code>, run 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-sh" data-lang="sh">$ protoc -I<span style="color:#f92672">=</span>$DIR echo.proto <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> --js_out<span style="color:#f92672">=</span>import_style<span style="color:#f92672">=</span>commonjs:$OUT_DIR</code></pre></div>
<p>The <code>import_style</code> option passed to the <code>--js_out</code> flag makes sure the
generated files will have CommonJS style <code>require()</code> statements.</p>
<p>To generate the gRPC-Web service client stub, first you need the gRPC-Web
protoc plugin. To compile the plugin <code>protoc-gen-grpc-web</code>, you need to run
this from the repo&rsquo;s root directory:</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-sh" data-lang="sh">$ cd grpc-web
$ sudo make install-plugin</code></pre></div>
<p>To generate the service client stub file, run this 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-sh" data-lang="sh">$ protoc -I<span style="color:#f92672">=</span>$DIR echo.proto <span style="color:#ae81ff">\
</span><span style="color:#ae81ff"></span> --grpc-web_out<span style="color:#f92672">=</span>import_style<span style="color:#f92672">=</span>commonjs,mode<span style="color:#f92672">=</span>grpcwebtext:$OUT_DIR</code></pre></div>
<p>In the <code>--grpc-web_out</code> param above:
- <code>mode</code> can be <code>grpcwebtext</code> (default) or <code>grpcweb</code>
- <code>import_style</code> can be <code>closure</code> (default) or <code>commonjs</code></p>
<p>Our command generates the client stub, by default, to the file
<code>echo_grpc_web_pb.js</code>.</p>
<h3 id="write-js-client-code">Write JS Client Code</h3>
<p>Now you are ready to write some JS client code. Put this in a <code>client.js</code> file.</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">EchoRequest</span>, <span style="color:#a6e22e">EchoResponse</span>} <span style="color:#f92672">=</span> <span style="color:#a6e22e">require</span>(<span style="color:#e6db74">&#39;./echo_pb.js&#39;</span>);
<span style="color:#66d9ef">const</span> {<span style="color:#a6e22e">EchoServiceClient</span>} <span style="color:#f92672">=</span> <span style="color:#a6e22e">require</span>(<span style="color:#e6db74">&#39;./echo_grpc_web_pb.js&#39;</span>);
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">echoService</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">EchoServiceClient</span>(<span style="color:#e6db74">&#39;http://localhost:8080&#39;</span>);
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">request</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">EchoRequest</span>();
<span style="color:#a6e22e">request</span>.<span style="color:#a6e22e">setMessage</span>(<span style="color:#e6db74">&#39;Hello World!&#39;</span>);
<span style="color:#a6e22e">echoService</span>.<span style="color:#a6e22e">echo</span>(<span style="color:#a6e22e">request</span>, {}, <span style="color:#66d9ef">function</span>(<span style="color:#a6e22e">err</span>, <span style="color:#a6e22e">response</span>) {
<span style="color:#75715e">// ...
</span><span style="color:#75715e"></span>});
</code></pre></div>
<p>You will need a <code>package.json</code> file</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-json" data-lang="json">{
<span style="color:#f92672">&#34;name&#34;</span>: <span style="color:#e6db74">&#34;grpc-web-commonjs-example&#34;</span>,
<span style="color:#f92672">&#34;dependencies&#34;</span>: {
<span style="color:#f92672">&#34;google-protobuf&#34;</span>: <span style="color:#e6db74">&#34;^3.6.1&#34;</span>,
<span style="color:#f92672">&#34;grpc-web&#34;</span>: <span style="color:#e6db74">&#34;^0.4.0&#34;</span>
},
<span style="color:#f92672">&#34;devDependencies&#34;</span>: {
<span style="color:#f92672">&#34;browserify&#34;</span>: <span style="color:#e6db74">&#34;^16.2.2&#34;</span>,
<span style="color:#f92672">&#34;webpack&#34;</span>: <span style="color:#e6db74">&#34;^4.16.5&#34;</span>,
<span style="color:#f92672">&#34;webpack-cli&#34;</span>: <span style="color:#e6db74">&#34;^3.1.0&#34;</span>
}
}</code></pre></div>
<h3 id="compile-the-js-library">Compile the JS Library</h3>
<p>Finally, putting all these together, we can compile all the relevant JS files
into one single JS library that can be used in the browser.</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-sh" data-lang="sh">$ npm install
$ npx webpack client.js</code></pre></div>
<p>Now embed <code>dist/main.js</code> into your project and see it in action!</p>
</div>
</div>
</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>