CINXE.COM
AIP-127: HTTP and gRPC Transcoding
<!DOCTYPE html> <html lang="en-US" class="glue-flexbox"> <head> <title>AIP-127: HTTP and gRPC Transcoding</title> <meta charset='utf-8'> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,maximum-scale=2"> <link href="//fonts.googleapis.com/css?family=Roboto:100,300,400,500,700|Google+Sans:400,500|Product+Sans:400&lang=en" rel="stylesheet"></link> <link rel="shortcut icon" href="/assets/favicon.ico"> <link rel="stylesheet" type="text/css" media="screen" href="//www.gstatic.com/glue/v22_1/glue.min.css"> <link rel="stylesheet" type="text/css" media="screen" href="/assets/css/style.css?v=acdbbe4d"> <link rel="stylesheet" type="text/css" media="print" href="/assets/css/print.css?v=acdbbe4d"> <script type="text/javascript" src="//code.jquery.com/jquery-3.4.0.min.js"></script> <script type="text/javascript" src="//www.gstatic.com/glue/latest/glue-detect.min.js"></script> <script type="text/javascript"> $('html').css('visibility', 'hidden'); $.when($.ready).then(() => { $('html').css('visibility', 'visible'); }); </script> <script type="text/javascript" src="/assets/js/global.js?v=acdbbe4d"></script> <script type="text/javascript" src="/assets/js/syntax.js"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-140054909-1"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-140054909-1'); </script> </head> <body> <!-- prettier-ignore --> <header class="glue-header glue-header--single"> <div class="glue-header__bar glue-header__bar--desktop glue-header__drawer"> <div class="glue-header__tier"> <!-- LOCK up--> <div class="glue-header__container"> <div class="glue-header__lock-up"> <div class="glue-header__logo"> <a class="glue-header__logo-link" href="/" title="Google"> <div class="glue-header__logo-container"> <svg role="img" aria-hidden="true" class="glue-header__logo-svg"> <use xlink:href="/assets/images/glue-icons.svg#google-color-logo"></use> </svg> </div> <p class="glue-header__logo--product">AIPs</p> </a> </div> <a href="#page-content" class="glue-header__skip-content"> <p class="glue-header__skip-content-text">Jump to Content</p> </a> </div> </div> <!-- LINK BAR--> <div class="glue-header__container glue-header__container--flex-auto"> <nav class="glue-header__link-bar"> <ul id="list-1" class="glue-header__list"> <li class="glue-header__item"> <a class="glue-header__link" href="/general" aria-level="1">Browse AIPs</a> </li> <li class="glue-header__item"> <a class="glue-header__link" href="/news" aria-level="1">News</a> </li> <li class="glue-header__item"> <a class="glue-header__link" href="/faq" aria-level="1">FAQ</a> </li> <li class="glue-header__item"> <a class="glue-header__link" href="/contributing" aria-level="1">Contributing</a> </li> <li class="glue-header__item"> <a class="glue-header__link" href="https://linter.aip.dev/" target="_blank" aria-level="1"> API Linter <svg role="img" class="glue-icon glue-icon--18px"> <use xlink:href="/assets/images/glue-icons.svg#open-in-new"></use> </svg> </a> </li> </ul> </nav> </div> <!-- CTA--> <div class="glue-header__container glue-header__container--cta"> <div class="glue-header__cta"> <div class="glue-sitesearch"> <form method="GET" action="/search"> <label for="q">Search this site</label> <input class="glue-sitesearch__input" type="text" name="q" id="q" placeholder="Search AIPs"> <button type="submit" class="glue-button glue-sitesearch__submit" title="Submit"> <svg role="img" class="glue-icon glue-icon--24px"> <use xlink:href="/assets/images/glue-icons.svg#search"></use> </svg> </button> </form> </div> <a href="https://github.com/aip-dev/google.aip.dev" target="_blank" class="glue-button glue-button--high-emphasis"> <img src="/assets/images/github.png" class="github-logo"> View on GitHub </a> </div> </div> </div> </div> <!-- Mobile header placeholder --> <div class="glue-header__bar glue-header__bar--mobile"> <div class="glue-header__tier"> <!-- LOCK up--> <div class="glue-header__container"> <div class="glue-header__lock-up"> <div class="glue-header__hamburger glue-header__hamburger--first-tier"> <div class="glue-header__hamburger-wrapper"> <button type="button" class="glue-header__drawer-toggle-btn" aria-controls="drawer" aria-expanded="false" aria-label="Open the navigation drawer"> <svg role="img" class="glue-icon glue-icon--24px"><use xlink:href="/assets/images/glue-icons.svg#menu"></use></svg> </button> </div> </div> <div class="glue-header__logo"> <a class="glue-header__logo-link" href="/" title="Google"> <div class="glue-header__logo-container"> <svg role="img" aria-hidden="true" class="glue-header__logo-svg"> <use xlink:href="/assets/images/glue-icons.svg#google-color-logo"></use> </svg> </div> <p class="glue-header__logo--product">AIPs</p> </a> </div> <!-- SKIP --> <a href="#page-content" class="glue-header__skip-content"> <p class="glue-header__skip-content-text">Jump to Content</p> </a> </div> </div> <!-- CTA --> <div class="glue-header__container"> <div class="glue-header__cta"> <a href="https://github.com/aip-dev/google.aip.dev" class="glue-button glue-button--high-emphasis"> <img src="/assets/images/github.png" class="github-logo"> View on GitHub </a> </div> </div> </div> </div> <div class="glue-header__drawer-backdrop"></div> </header> <div class="glue-page"> <main role="main" id="page-content"> <nav id="aip-nav" class="docs-component-nav"> <ul class="nav-list"> <li class="nav-item nav-item-header">AIPs by Scope</li> <li class="nav-item"> <a href="/general">General</a> </li> <li class="nav-item"> <a href="/cloud">Google Cloud Platform</a> </li> <li class="nav-item"> <a href="/auth">Auth</a> </li> <li class="nav-item"> <a href="/client-libraries">Client libraries</a> </li> <li class="nav-item"> <a href="/apps">GSuite</a> </li> <li class="nav-item"> <a href="/aog">Actions on Google</a> </li> <li class="nav-item nav-item-header">AIPs</li> <li class="nav-item"> <a href="/1"> <span class="aip-number">1</span> AIP Purpose and Guidelines </a> </li> <li class="nav-item"> <a href="/2"> <span class="aip-number">2</span> AIP Numbering </a> </li> <li class="nav-item"> <a href="/3"> <span class="aip-number">3</span> AIP Versioning </a> </li> <li class="nav-item"> <a href="/8"> <span class="aip-number">8</span> AIP Style and Guidance </a> </li> <li class="nav-item"> <a href="/9"> <span class="aip-number">9</span> Glossary </a> </li> <li class="nav-item"> <a href="/100"> <span class="aip-number">100</span> API Design Review FAQ </a> </li> <li class="nav-item"> <a href="/111"> <span class="aip-number">111</span> Planes </a> </li> <li class="nav-item"> <a href="/121"> <span class="aip-number">121</span> Resource-oriented design </a> </li> <li class="nav-item"> <a href="/122"> <span class="aip-number">122</span> Resource names </a> </li> <li class="nav-item"> <a href="/123"> <span class="aip-number">123</span> Resource types </a> </li> <li class="nav-item"> <a href="/124"> <span class="aip-number">124</span> Resource association </a> </li> <li class="nav-item"> <a href="/126"> <span class="aip-number">126</span> Enumerations </a> </li> <li class="nav-item nav-item-active"> <a href="/127"> <span class="aip-number">127</span> HTTP and gRPC Transcoding </a> </li> <li class="nav-item"> <a href="/128"> <span class="aip-number">128</span> Declarative-friendly interfaces </a> </li> <li class="nav-item"> <a href="/129"> <span class="aip-number">129</span> Server-Modified Values and Defaults </a> </li> <li class="nav-item"> <a href="/130"> <span class="aip-number">130</span> Methods </a> </li> <li class="nav-item"> <a href="/131"> <span class="aip-number">131</span> Standard methods: Get </a> </li> <li class="nav-item"> <a href="/132"> <span class="aip-number">132</span> Standard methods: List </a> </li> <li class="nav-item"> <a href="/133"> <span class="aip-number">133</span> Standard methods: Create </a> </li> <li class="nav-item"> <a href="/134"> <span class="aip-number">134</span> Standard methods: Update </a> </li> <li class="nav-item"> <a href="/135"> <span class="aip-number">135</span> Standard methods: Delete </a> </li> <li class="nav-item"> <a href="/136"> <span class="aip-number">136</span> Custom methods </a> </li> <li class="nav-item"> <a href="/140"> <span class="aip-number">140</span> Field names </a> </li> <li class="nav-item"> <a href="/141"> <span class="aip-number">141</span> Quantities </a> </li> <li class="nav-item"> <a href="/142"> <span class="aip-number">142</span> Time and duration </a> </li> <li class="nav-item"> <a href="/143"> <span class="aip-number">143</span> Standardized codes </a> </li> <li class="nav-item"> <a href="/144"> <span class="aip-number">144</span> Repeated fields </a> </li> <li class="nav-item"> <a href="/145"> <span class="aip-number">145</span> Ranges </a> </li> <li class="nav-item"> <a href="/146"> <span class="aip-number">146</span> Generic fields </a> </li> <li class="nav-item"> <a href="/147"> <span class="aip-number">147</span> Sensitive fields </a> </li> <li class="nav-item"> <a href="/148"> <span class="aip-number">148</span> Standard fields </a> </li> <li class="nav-item"> <a href="/149"> <span class="aip-number">149</span> Unset field values </a> </li> <li class="nav-item"> <a href="/151"> <span class="aip-number">151</span> Long-running operations </a> </li> <li class="nav-item"> <a href="/152"> <span class="aip-number">152</span> Jobs </a> </li> <li class="nav-item"> <a href="/153"> <span class="aip-number">153</span> Import and export </a> </li> <li class="nav-item"> <a href="/154"> <span class="aip-number">154</span> Resource freshness validation </a> </li> <li class="nav-item"> <a href="/155"> <span class="aip-number">155</span> Request identification </a> </li> <li class="nav-item"> <a href="/156"> <span class="aip-number">156</span> Singleton resources </a> </li> <li class="nav-item"> <a href="/157"> <span class="aip-number">157</span> Partial responses </a> </li> <li class="nav-item"> <a href="/158"> <span class="aip-number">158</span> Pagination </a> </li> <li class="nav-item"> <a href="/159"> <span class="aip-number">159</span> Reading across collections </a> </li> <li class="nav-item"> <a href="/160"> <span class="aip-number">160</span> Filtering </a> </li> <li class="nav-item"> <a href="/161"> <span class="aip-number">161</span> Field masks </a> </li> <li class="nav-item"> <a href="/162"> <span class="aip-number">162</span> Resource Revisions </a> </li> <li class="nav-item"> <a href="/163"> <span class="aip-number">163</span> Change validation </a> </li> <li class="nav-item"> <a href="/164"> <span class="aip-number">164</span> Soft delete </a> </li> <li class="nav-item"> <a href="/165"> <span class="aip-number">165</span> Criteria-based delete </a> </li> <li class="nav-item"> <a href="/180"> <span class="aip-number">180</span> Backwards compatibility </a> </li> <li class="nav-item"> <a href="/181"> <span class="aip-number">181</span> Stability levels </a> </li> <li class="nav-item"> <a href="/182"> <span class="aip-number">182</span> External software dependencies </a> </li> <li class="nav-item"> <a href="/185"> <span class="aip-number">185</span> API Versioning </a> </li> <li class="nav-item"> <a href="/191"> <span class="aip-number">191</span> File and directory structure </a> </li> <li class="nav-item"> <a href="/192"> <span class="aip-number">192</span> Documentation </a> </li> <li class="nav-item"> <a href="/193"> <span class="aip-number">193</span> Errors </a> </li> <li class="nav-item"> <a href="/194"> <span class="aip-number">194</span> Automatic retry configuration </a> </li> <li class="nav-item"> <a href="/200"> <span class="aip-number">200</span> Precedent </a> </li> <li class="nav-item"> <a href="/202"> <span class="aip-number">202</span> Fields </a> </li> <li class="nav-item"> <a href="/203"> <span class="aip-number">203</span> Field behavior documentation </a> </li> <li class="nav-item"> <a href="/205"> <span class="aip-number">205</span> Beta-blocking changes </a> </li> <li class="nav-item"> <a href="/210"> <span class="aip-number">210</span> Unicode </a> </li> <li class="nav-item"> <a href="/211"> <span class="aip-number">211</span> Authorization checks </a> </li> <li class="nav-item"> <a href="/213"> <span class="aip-number">213</span> Common components </a> </li> <li class="nav-item"> <a href="/214"> <span class="aip-number">214</span> Resource expiration </a> </li> <li class="nav-item"> <a href="/215"> <span class="aip-number">215</span> API-specific protos </a> </li> <li class="nav-item"> <a href="/216"> <span class="aip-number">216</span> States </a> </li> <li class="nav-item"> <a href="/217"> <span class="aip-number">217</span> Unreachable resources </a> </li> <li class="nav-item"> <a href="/231"> <span class="aip-number">231</span> Batch methods: Get </a> </li> <li class="nav-item"> <a href="/233"> <span class="aip-number">233</span> Batch methods: Create </a> </li> <li class="nav-item"> <a href="/234"> <span class="aip-number">234</span> Batch methods: Update </a> </li> <li class="nav-item"> <a href="/235"> <span class="aip-number">235</span> Batch methods: Delete </a> </li> <li class="nav-item"> <a href="/236"> <span class="aip-number">236</span> Policy preview </a> </li> </ul> </nav> <section id="jump-content"> <aside id="aip-sidebar" class="docs-component-sidebar"> <table id="aip-summary"> <tr><th colspan="2">HTTP and gRPC Transcoding</th></tr> <tr><td>Number</td><td>127</td></tr> <tr><td>Permalink</td><td><a href="https://google.aip.dev/127">google.aip.dev/127</a></td></tr> <tr><td>State</td><td>Approved</td></tr> <tr><td>Created</td><td>2019-08-22</td></tr> <tr><td>Updated</td><td>2019-08-22</td></tr> </table> <section id="aip-toc" class="docs-component-sidebar-toc"> <div class="toc"><span class="toctitle">Contents</span><ul> <li><a href="#guidance">Guidance</a><ul> <li><a href="#http-method-and-path">HTTP method and path</a></li> <li><a href="#multiple-uri-bindings">Multiple URI bindings</a></li> </ul> </li> <li><a href="#changelog">Changelog</a></li> </ul> </div> </section> <section class="docs-component-sidebar-actions"> <ul> <li><a href="https://github.com/aip-dev/google.aip.dev/issues/">File Bug</a></li> <li><a href="https://github.com/aip-dev/google.aip.dev/blob/master/aip/general/0127.md">View source</a></li> <li><a href="https://github.com/aip-dev/google.aip.dev/edit/master/aip/general/0127.md">Edit this page</a></li> </ul> </section> </aside> <section id="aip-main" class="docs-component-main"> <section class="section-breadcrumbs"> <nav class="glue-breadcrumbs glue-mod-mt-std glue-mod-mb-std" aria-label="You are here." > <ol class="glue-breadcrumbs__list aip-breadcrumbs"> <li class="glue-breadcrumbs__item" aria-level="1"> <a class="glue-breadcrumbs__link" href="/"> API Improvement Proposals </a> </li> <li class="glue-breadcrumbs__item" aria-level="2"> <a class="glue-breadcrumbs__link" href="/general"> General AIPs </a> </li> <li class="glue-breadcrumbs__item glue-breadcrumbs__item--active" aria-level="3"> HTTP and gRPC Transcoding </li> </ol> </nav> </section> <h4 class="aip-number">AIP-127</h4> <h1 id="http-and-grpc-transcoding">HTTP and gRPC Transcoding</h1> <p>APIs that follow <a href="/121">resource-oriented design</a> are defined using <a href="https://en.wikipedia.org/wiki/Remote_procedure_call">RPCs</a>, but the resource-oriented design framework allows them to also be presented as APIs that largely follow REST/JSON conventions. This is important in order to help developers use their existing knowledge: over 80% of the public APIs available follow most REST conventions, and developers are accustomed to that pattern.</p> <h2 id="guidance">Guidance</h2> <p>APIs <strong>must</strong> provide HTTP definitions for each RPC that they define, except for bi-directional streaming RPCs, which can not be natively supported using HTTP/1.1. When providing a bi-directional streaming method, an API <strong>should</strong> also offer an alternative method that does not rely on bi-directional streaming.</p> <h3 id="http-method-and-path">HTTP method and path</h3> <p>When using protocol buffers, each RPC <strong>must</strong> define the HTTP method and path using the <code>google.api.http</code> annotation:</p> <div class="highlight language-proto"><pre><span></span><code><span class="k">rpc</span> <span class="n">CreateBook</span><span class="p">(</span><span class="n">CreateBookRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">Book</span><span class="p">)</span> <span class="p">{</span> <span class="k">option</span> <span class="p">(</span><span class="n">google.api.http</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="n">post</span><span class="o">:</span> <span class="s">"/v1/{parent=publishers/*}/books"</span> <span class="n">body</span><span class="o">:</span> <span class="s">"book"</span> <span class="p">};</span> <span class="p">}</span> <span class="kd">message</span> <span class="nc">CreateBookRequest</span> <span class="p">{</span> <span class="c1">// The publisher who will publish this book.</span> <span class="c1">// When using HTTP/JSON, this field is automatically populated based</span> <span class="c1">// on the URI, because of the `{parent=publishers/*}` syntax.</span> <span class="kt">string</span> <span class="na">parent</span> <span class="o">=</span> <span class="mi">1</span> <span class="p">[</span> <span class="p">(</span><span class="n">google.api.field_behavior</span><span class="p">)</span> <span class="o">=</span> <span class="n">REQUIRED</span><span class="p">,</span> <span class="p">(</span><span class="n">google.api.resource_reference</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="n">child_type</span><span class="o">:</span> <span class="s">"library.googleapis.com/Book"</span> <span class="p">}];</span> <span class="c1">// The book to create.</span> <span class="c1">// When using HTTP/JSON, this field is populated based on the HTTP body,</span> <span class="c1">// because of the `body: "book"` syntax.</span> <span class="n">Book</span> <span class="na">book</span> <span class="o">=</span> <span class="mi">2</span> <span class="p">[(</span><span class="n">google.api.field_behavior</span><span class="p">)</span> <span class="o">=</span> <span class="n">REQUIRED</span><span class="p">];</span> <span class="c1">// The user-specified ID for the book.</span> <span class="c1">// When using HTTP/JSON, this field is populated based on a query string</span> <span class="c1">// argument, such as `?bookId=foo`. This is the fallback for fields that</span> <span class="c1">// are not included in either the URI or the body.</span> <span class="c1">// Note that clients use camelCase format to communicate the field names</span> <span class="c1">// to the service.</span> <span class="kt">string</span> <span class="na">book_id</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="p">}</span> </code></pre></div> <ul> <li>The first key (<code>post</code> in this example) corresponds to the HTTP method. RPCs <strong>may</strong> use <code>get</code>, <code>post</code>, <code>patch</code>, or <code>delete</code>.<ul> <li>RPCs <strong>must</strong> use the prescribed HTTP verb for each standard method, as discussed in <a href="/131">AIP-131</a>, <a href="/132">AIP-132</a>, <a href="/133">AIP-133</a>, <a href="/134">AIP-134</a>, and <a href="/135">AIP-135</a></li> <li>RPCs <strong>should</strong> use the prescribed HTTP verb for custom methods, as discussed in <a href="/136">AIP-136</a>.</li> <li>RPCs <strong>should not</strong> use <code>put</code> or <code>custom</code>.</li> </ul> </li> <li>The corresponding value represents the URI.<ul> <li>URIs <strong>must</strong> use the <code>{foo=bar/*}</code> syntax to represent a variable that should be populated in the request proto. When extracting a <a href="/122">resource name</a>, the variable <strong>must</strong> include the entire resource name, not just the ID component.</li> <li>URIs <strong>may</strong> use nested fields for their variable names. (Additionally, <a href="/134">AIP-134</a> mandates this for <code>Update</code> requests.)</li> <li>URIs <strong>must</strong> use the <code>*</code> character to represent ID components, which matches all URI-safe characters except for <code>/</code>. URIs <strong>may</strong> use <code>**</code> as the final segment of a URI if matching <code>/</code> is required.</li> </ul> </li> <li>The <code>body</code> key defines which single top-level field in the request will be sent as the HTTP body. If the body is <code>*</code>, then this indicates that the request object itself is the HTTP body. The request body is encoded as JSON as defined by protocol buffers' canonical <a href="https://developers.google.com/protocol-buffers/docs/proto3#json">JSON encoding</a>.<ul> <li>RPCs <strong>must not</strong> define a <code>body</code> at all for RPCs that use the <code>GET</code> or <code>DELETE</code> HTTP verbs.</li> <li>RPCs <strong>must</strong> use the prescribed <code>body</code> for Create (<a href="/133">AIP-133</a>) and Update (<a href="/134">AIP-134</a>) requests.</li> <li>RPCs <strong>should</strong> use the prescribed <code>body</code> for custom methods (<a href="/136">AIP-136</a>).</li> <li>The <code>body</code> <strong>must not</strong> contain a nested field (or use the <code>.</code> character),</li> <li>The <code>body</code> <strong>must not</strong> be the same as a URI parameter.</li> <li>The <code>body</code> <strong>must not</strong> be a <code>repeated</code> field.</li> <li>Fields <strong>should not</strong> use the <code>json_name</code> annotation to alter the field name in JSON, unless doing so for backwards-compatibility reasons.</li> </ul> </li> </ul> <p><strong>Note:</strong> Bi-directional streaming RPCs should not include a <code>google.api.http</code> annotation at all. If feasible, the service <strong>should</strong> provide non-streaming equivalent RPCs.</p> <h3 id="multiple-uri-bindings">Multiple URI bindings</h3> <p>Occasionally, an RPC needs to correspond to more than one URI:</p> <div class="highlight language-proto"><pre><span></span><code><span class="k">rpc</span> <span class="n">CreateBook</span><span class="p">(</span><span class="n">CreateBookRequest</span><span class="p">)</span> <span class="k">returns</span> <span class="p">(</span><span class="n">Book</span><span class="p">)</span> <span class="p">{</span> <span class="k">option</span> <span class="p">(</span><span class="n">google.api.http</span><span class="p">)</span> <span class="o">=</span> <span class="p">{</span> <span class="n">post</span><span class="o">:</span> <span class="s">"/v1/{parent=publishers/*}/books"</span> <span class="n">body</span><span class="o">:</span> <span class="s">"book"</span> <span class="n">additional_bindings</span><span class="o">:</span> <span class="p">{</span> <span class="n">post</span><span class="o">:</span> <span class="s">"/v1/{parent=authors/*}/books"</span> <span class="n">body</span><span class="o">:</span> <span class="s">"book"</span> <span class="p">}</span> <span class="n">additional_bindings</span><span class="o">:</span> <span class="p">{</span> <span class="n">post</span><span class="o">:</span> <span class="s">"/v1/books"</span> <span class="n">body</span><span class="o">:</span> <span class="s">"book"</span> <span class="p">}</span> <span class="p">};</span> <span class="p">}</span> </code></pre></div> <ul> <li>RPCs <strong>may</strong> define any number of additional bindings. The structure is identical to the <code>google.api.http</code> annotation (in fact, it is a recursive reference).</li> <li>RPCs <strong>must not</strong> define an additional binding within an additional binding.</li> <li>The <code>body</code> clause <strong>must</strong> be identical in the top-level annotation and each additional binding.</li> </ul> <h2 id="changelog">Changelog</h2> <ul> <li><strong>2022-08-18</strong>: Added the comment that query string parameter names are in camelCase.</li> <li><strong>2021-01-06</strong>: Added clarification around <code>body</code> and nested fields.</li> <li><strong>2019-09-23</strong>: Added a statement about request body encoding, and guidance discouraging <code>json_name</code>.</li> </ul> <!-- prettier-ignore-start --> <!-- prettier-ignore-end --> <footer> Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. <span class="no-print">For details, see <a href="/licensing">content licensing</a>.</span> </footer> </section> </section> </main> </div> <script src="//www.gstatic.com/external_hosted/hammerjs/v2_0_2/hammer.min.js"></script> <script src="//www.gstatic.com/glue/v22_1/glue-vanilla.min.js"></script> <script type="text/javascript"> const headerElement = document.querySelector('.glue-header'); if (headerElement) { new window.glue.ui.header.Header(headerElement); } </script> </body> </html>