grpc-gateway Documentation

GRPC to JSON proxy generator following the gRPC HTTP spec

20,006 stars Go Go 1 file · ~50,306 tokens #go#grpc#grpc-gateway#openapi#rest-api#restful-api#swagger
RAW Doc

Technical Documentation: grpc-ecosystem/grpc-gateway

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

About

The gRPC-Gateway is a plugin of the Google protocol buffers compiler
protoc.
It reads protobuf service definitions and generates a reverse-proxy server which
translates a RESTful HTTP API into gRPC. This server is generated according to the
google.api.http
annotations in your service definitions.

This helps you provide your APIs in both gRPC and RESTful style at the same time.

Docs

You can read our docs at:

Testimonials

We use the gRPC-Gateway to serve millions of API requests per day,
and have been since 2018 and through all of that,
we have never had any issues with it.

- William Mill, Ad Hoc

Background

gRPC is great -- it generates API clients and server stubs in many programming
languages, it is fast, easy-to-use, bandwidth-efficient and its design is
combat-proven by Google. However, you might still want to provide a traditional
RESTful JSON API as well. Reasons can range from maintaining
backward-compatibility, supporting languages or clients that are not well supported by
gRPC, to simply maintaining the aesthetics and tooling involved with a RESTful
JSON architecture.

This project aims to provide that HTTP+JSON interface to your gRPC service.
A small amount of configuration in your service to attach HTTP semantics is all
that's needed to generate a reverse-proxy with this library.

Installation

Compile from source

The following instructions assume you are using
Go Modules for dependency
management. Use a
tool dependency
to track the versions of the following executable packages:

For Go 1.24 and later, prefer the tool directive in go.mod described in the "Tracking Tools in go.mod" section. The following blank-import pattern is mainly useful for projects that are not using Go 1.24 yet.

go
// +build tools

package tools

import (
    _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway"
    _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
    _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
    _ "google.golang.org/protobuf/cmd/protoc-gen-go"
)

Run go mod tidy to resolve the versions. Install by running

sh
go install \
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
    github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
    google.golang.org/protobuf/cmd/protoc-gen-go \
    google.golang.org/grpc/cmd/protoc-gen-go-grpc

This will place four binaries in your $GOBIN;

  • protoc-gen-grpc-gateway
  • protoc-gen-openapiv2
  • protoc-gen-go
  • protoc-gen-go-grpc

Make sure that your $GOBIN is in your $PATH.

If you want to emit OpenAPI 3.1 instead of (or in addition to) Swagger 2.0,
install protoc-gen-openapiv3 as well:

sh
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3

⚠️ Alpha. protoc-gen-openapiv3 is new and its output is not yet
stable — the emitted JSON shape for oneofs, wrappers, enums, and similar
constructs may change in response to real-world feedback before the
plugin graduates. Don't rely on the exact spec bytes being stable across
minor releases; the proto-to-OpenAPI mapping rules are likely to
tighten, and tooling-compatibility compromises (documented in the
generator source) may be revisited as consumer OpenAPI 3.1 support
matures. protoc-gen-openapiv2 is the production-stable option.

See OpenAPI 3.1 Output
for what it supports and how it differs from protoc-gen-openapiv2.

**Using the `tool` Directive in Go 1.24**

Starting from Go 1.24, the tool directive in go.mod provides a structured way to track and manage executable dependencies. This replaces the previous workaround of using a separate tools.go file with blank imports.

**Tracking Tools in `go.mod`**

Instead of manually importing tool dependencies in a Go source file, you can now use the tool directive in go.mod to declare the tools your project depends on. For example:

go
module tools

go 1.24

tool (
	github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
	github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
	google.golang.org/grpc/cmd/protoc-gen-go-grpc
	google.golang.org/protobuf/cmd/protoc-gen-go
)

**Managing Tool Dependencies**

To add tools to your module, use the -tool flag with go get:

sh
go get -tool github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
go get -tool github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
go get -tool google.golang.org/protobuf/cmd/protoc-gen-go
go get -tool google.golang.org/grpc/cmd/protoc-gen-go-grpc

This automatically updates go.mod, adding the tools under the tool directive along with require statements to ensure version tracking.

Install Tools

Once the tool dependencies are properly recorded in the go.mod file, simply execute the following command in the root directory of your project:

sh
go install tool

This will place four binaries in your $GOBIN;

  • protoc-gen-grpc-gateway
  • protoc-gen-openapiv2
  • protoc-gen-go
  • protoc-gen-go-grpc

Make sure that your $GOBIN is in your $PATH.

Download the binaries

You may alternatively download the binaries from the GitHub releases page.
We generate SLSA3 signatures using the OpenSSF's slsa-framework/slsa-github-generator during the release process. To verify a release binary:

  1. Install the verification tool from slsa-framework/slsa-verifier#installation.
  2. Download the provenance file attestation.intoto.jsonl from the GitHub releases page.
  3. Run the verifier:
shell
slsa-verifier -artifact-path <the-binary> -provenance attestation.intoto.jsonl -source github.com/grpc-ecosystem/grpc-gateway -tag <the-tag>

Alternatively, see the section on remotely managed plugin versions below.

Usage

1.Define your [gRPC](https://grpc.io/docs/) service using protocol buffers

your_service.proto:

protobuf
syntax = "proto3";
 package your.service.v1;
 option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1";

 message StringMessage {
   string value = 1;
 }

 service YourService {
   rpc Echo(StringMessage) returns (StringMessage) {}
 }

2. Generate gRPC stubs

This step generates the gRPC stubs that you can use to implement the service and consume from clients:

Here's an example buf.gen.yaml you can use to generate the stubs with buf:

yaml
version: v2
plugins:
  - local: protoc-gen-go
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-go-grpc
    out: gen/go
    opt:
      - paths=source_relative

With this file in place, you can generate your files using buf generate.

For a complete example of using buf generate to generate protobuf stubs, see
the boilerplate repo.
For more information on generating the stubs with buf, see
the official documentation.

If you are using protoc to generate stubs, here's an example of what a command
might look like:

sh
protoc -I . \
    --go_out ./gen/go/ --go_opt paths=source_relative \
    --go-grpc_out ./gen/go/ --go-grpc_opt paths=source_relative \
    your/service/v1/your_service.proto

3. Implement your service in gRPC as usual.

4. Generate reverse-proxy using `protoc-gen-grpc-gateway`

At this point, you have 3 options:

  • no further modifications, use the default mapping to HTTP semantics (method, path, etc.)
    • this will work on any .proto file, but will not allow setting HTTP paths, request parameters or similar
  • additional .proto modifications to use a custom mapping
    • relies on parameters in the .proto file to set custom HTTP mappings
  • no .proto modifications, but use an external configuration file
    • relies on an external configuration file to set custom HTTP mappings
    • mostly useful when the source proto file isn't under your control

1. Using the default mapping

This requires no additional modification to the .proto file but does require enabling a specific option when executing the plugin.
The generate_unbound_methods should be enabled.

Here's what a buf.gen.yaml file might look like with this option enabled:

yaml
version: v2
plugins:
  - local: protoc-gen-go
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-go-grpc
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-grpc-gateway
    out: gen/go
    opt:
      - paths=source_relative
      - generate_unbound_methods=true

With protoc (just the grpc-gateway stubs):

sh
protoc -I . --grpc-gateway_out ./gen/go \
    --grpc-gateway_opt paths=source_relative \
    --grpc-gateway_opt generate_unbound_methods=true \
    your/service/v1/your_service.proto

2. With custom annotations

Add a google.api.http
annotation to your .proto file

your_service.proto:

diff
syntax = "proto3";
 package your.service.v1;
 option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1";
+
+import "google/api/annotations.proto";
+
 message StringMessage {
   string value = 1;
 }

 service YourService {
-  rpc Echo(StringMessage) returns (StringMessage) {}
+  rpc Echo(StringMessage) returns (StringMessage) {
+    option (google.api.http) = {
+      post: "/v1/example/echo"
+      body: "*"
+    };
+  }
 }

You will need to provide the required third party protobuf files to the protobuf compiler.
If you are using buf, this dependency can
be added to the deps array in your buf.yaml under the name
buf.build/googleapis/googleapis:

yaml
version: v2
name: buf.build/yourorg/myprotos
deps:
  - buf.build/googleapis/googleapis

Always run buf dep update after adding a dependency to your buf.yaml.

See a_bit_of_everything.proto
for examples of more annotations you can add to customize gateway behavior
and generated OpenAPI output.

Here's what a buf.gen.yaml file might look like:

yaml
version: v2
plugins:
  - local: protoc-gen-go
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-go-grpc
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-grpc-gateway
    out: gen/go
    opt:
      - paths=source_relative

If you are using protoc to generate stubs, you need to ensure the required
dependencies are available to the compiler at compile time. These can be found
by manually cloning and copying the relevant files from the
googleapis repository, and providing
them to protoc when running. The files you will need are:

text
google/api/annotations.proto
google/api/field_behavior.proto
google/api/http.proto
google/api/httpbody.proto

Here's what a protoc execution might look like:

sh
protoc -I . --grpc-gateway_out ./gen/go \
    --grpc-gateway_opt paths=source_relative \
    your/service/v1/your_service.proto

3. External configuration

If you do not want to (or cannot) modify the proto file for use with gRPC-Gateway you can
alternatively use an external
gRPC Service Configuration file.
Check our documentation
for more information. This is best combined with the standalone=true option
to generate a file that can live in its own package, separate from the files
generated by the source protobuf file.

Here's what a buf.gen.yaml file might look like with this option enabled:

yaml
version: v2
plugins:
  - local: protoc-gen-go
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-go-grpc
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-grpc-gateway
    out: gen/go
    opt:
      - paths=source_relative
      - grpc_api_configuration=path/to/config.yaml
      - standalone=true

With protoc (just the grpc-gateway stubs):

sh
protoc -I . --grpc-gateway_out ./gen/go \
    --grpc-gateway_opt paths=source_relative \
    --grpc-gateway_opt grpc_api_configuration=path/to/config.yaml \
    --grpc-gateway_opt standalone=true \
    your/service/v1/your_service.proto

5. Write an entrypoint for the HTTP reverse-proxy server

go
package main

import (
  "context"
  "flag"
  "net/http"

  "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
  "google.golang.org/grpc"
  "google.golang.org/grpc/credentials/insecure"
  "google.golang.org/grpc/grpclog"

  gw "github.com/yourorg/yourrepo/proto/gen/go/your/service/v1/your_service"  // Update
)

var (
  // command-line options:
  // gRPC server endpoint
  grpcServerEndpoint = flag.String("grpc-server-endpoint",  "localhost:9090", "gRPC server endpoint")
)

func run() error {
  ctx := context.Background()
  ctx, cancel := context.WithCancel(ctx)
  defer cancel()

  // Register gRPC server endpoint
  // Note: Make sure the gRPC server is running properly and accessible
  mux := runtime.NewServeMux()
  opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
  err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux,  *grpcServerEndpoint, opts)
  if err != nil {
    return err
  }

  // Start HTTP server (and proxy calls to gRPC server endpoint)
  return http.ListenAndServe(":8081", mux)
}

func main() {
  flag.Parse()

  if err := run(); err != nil {
    grpclog.Fatal(err)
  }
}

6. (Optional) Generate OpenAPI definitions using `protoc-gen-openapiv2`

Here's what a buf.gen.yaml file might look like:

yaml
version: v2
plugins:
  - local: protoc-gen-go
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-go-grpc
    out: gen/go
    opt:
      - paths=source_relative
  - local: protoc-gen-grpc-gateway
    out: gen/go
    opt:
      - paths=source_relative
      - generate_unbound_methods=true
  - local: protoc-gen-openapiv2
    out: gen/go

To use the custom protobuf annotations supported by protoc-gen-openapiv2, we need
another dependency added to our protobuf generation step. If you are using
buf, you can add the buf.build/grpc-ecosystem/grpc-gateway dependency
to your deps array:

yaml
version: v2
name: buf.build/yourorg/myprotos
deps:
  - buf.build/googleapis/googleapis
  - buf.build/grpc-ecosystem/grpc-gateway

With protoc (just the swagger file):

sh
protoc -I . --openapiv2_out ./gen/openapiv2 \
    your/service/v1/your_service.proto

If you are using protoc to generate stubs, you will need to copy the protobuf
files from the protoc-gen-openapiv2/options directory of this repository,
and providing them to protoc when running.

Note that this plugin also supports generating OpenAPI definitions for unannotated methods;
use the generate_unbound_methods option to enable this.

It is possible with the HTTP mapping for a gRPC service method to create duplicate mappings
with the only difference being constraints on the path parameter.

/v1/{name=projects/*} and /v1/{name=organizations/*} both become /v1/{name}. When
this occurs the plugin will rename the path parameter with a "_1" (or "_2" etc) suffix
to differentiate the different operations. So in the above example, the 2nd path would become
/v1/{name_1=organizations/*}. This can also cause OpenAPI clients to URL encode the "/" that is
part of the path parameter as that is what OpenAPI defines in the specification. To allow gRPC gateway to
accept the URL encoded slash and still route the request, use the UnescapingModeAllCharacters or
UnescapingModeLegacy (which is the default currently though may change in future versions). See
Customizing Your Gateway
for more information.

Alternative: OpenAPI 3.1 with `protoc-gen-openapiv3`

⚠️ Alpha. protoc-gen-openapiv3 is new and its output is not yet
stable. Expect breaking changes to the emitted JSON shape (oneof
encodings, wrapper types, enum form, path-template expansion, etc.)
between minor releases while the mapping rules settle in response to
real-world feedback. Use it if you want to follow that evolution;
otherwise protoc-gen-openapiv2 remains the stable choice.

protoc-gen-openapiv3 is a separate generator that emits OpenAPI
3.1.0 JSON directly from google.api.http annotations. It's a good
choice when your downstream tooling requires 3.1, when you want the richer
JSON Schema 2020-12 constructs (proper oneOf encoding for proto oneofs,
spec-accurate literal expansion of constrained path templates like
{name=shelves/*/books/*}, etc.).

Add it to your buf.gen.yaml alongside (or instead of) protoc-gen-openapiv2:

yaml
version: v2
plugins:
  - local: protoc-gen-openapiv3
    out: gen/openapiv3

Or invoke it directly with protoc:

sh
protoc -I. --openapiv3_out=./gen/openapiv3 your/service/v1/your_service.proto

A .openapi.json file appears next to each proto file that declares HTTP
bindings; files with no HTTP-bound services produce no output.
See OpenAPI 3.1 Output for
more information about the capabilities of protoc-gen-openapiv3.

Usage with remote plugins

As an alternative to all of the above, you can use buf with
remote plugins
to manage plugin versions and generation. An example buf.gen.yaml using remote
plugin generation looks like this:

yaml
version: v2
plugins:
  - remote: buf.build/protocolbuffers/go:v1.31.0
    out: gen/go
    opt:
      - paths=source_relative
  - remote: buf.build/grpc/go:v1.3.0
    out: gen/go
    opt:
      - paths=source_relative
  - remote: buf.build/grpc-ecosystem/gateway:v2.16.2
    out: gen/go
    opt:
      - paths=source_relative
  - remote: buf.build/grpc-ecosystem/openapiv2:v2.16.2
    out: gen/openapiv2

This requires no local installation of any plugins. Be careful to use the same
version of the generator as the runtime library, i.e. if using v2.16.2, run

shell
$ go get github.com/grpc-ecosystem/grpc-gateway/[email protected]

To get the same version of the runtime in your go.mod.

Note that usage of remote plugins is incompatible with usage of external configuration files like grpc_api_configuration.

Video intro

This GopherCon UK 2019 presentation from our maintainer @JohanBrandhorst provides a good intro to using the gRPC-Gateway. It uses the following boilerplate repo as a base: https://github.com/johanbrandhorst/grpc-gateway-boilerplate.

Parameters and flags

When using buf to generate stubs, flags and parameters are passed through
the opt field in your buf.gen.yaml file, for example:

yaml
version: v2
plugins:
  - local: protoc-gen-grpc-gateway
    out: gen/go
    opt:
      - paths=source_relative
      - grpc_api_configuration=path/to/config.yaml
      - standalone=true

During code generation with protoc, flags to gRPC-Gateway tools must be passed
through protoc using one of 2 patterns:

  • as part of the --<tool_suffix>_out protoc parameter: --<tool_suffix>_out=<flags>:
sh
--grpc-gateway_out=repeated_path_param_separator=ssv:.
--openapiv2_out=repeated_path_param_separator=ssv:.
  • using additional --<tool_suffix>_opt parameters: --<tool_suffix>_opt=<flag>[,<flag>]*
sh
--grpc-gateway_opt repeated_path_param_separator=ssv
--openapiv2_opt repeated_path_param_separator=ssv

More examples

More examples are available under the examples/internal directory.

  • proto/examplepb/echo_service.proto, proto/examplepb/a_bit_of_everything.proto, proto/examplepb/unannotated_echo_service.proto: service definition
    • proto/examplepb/echo_service.pb.go, proto/examplepb/a_bit_of_everything.pb.go, proto/examplepb/unannotated_echo_service.pb.go: [generated] stub of the service
    • proto/examplepb/echo_service.pb.gw.go, proto/examplepb/a_bit_of_everything.pb.gw.go, proto/examplepb/unannotated_echo_service.pb.gw.go: [generated] reverse proxy for the service
    • proto/examplepb/unannotated_echo_service.yaml: gRPC API Configuration for unannotated_echo_service.proto
  • server/main.go: service implementation
  • cmd/example-gateway-server/: entrypoint of the generated reverse proxy

To use the same port for custom HTTP handlers (e.g. serving swagger.json),
gRPC-Gateway, and a gRPC server, see
this example by CoreOS
(and its accompanying blog post).

This example by neiro.ai (and its accompanying blog post) shows how mediafiles using multipart/form-data can be integrated into rpc messages using a middleware.

See also these community example repositories:

Features

Supported

  • Generating JSON API handlers.
  • Method parameters in the request body.
  • Method parameters in the request path.
  • Method parameters in the query string.
  • Enum fields in the path parameter (including repeated enum fields).
  • Mapping streaming APIs to newline-delimited JSON streams.
  • Mapping HTTP headers with Grpc-Metadata- prefix to gRPC metadata (prefixed with grpcgateway-)
  • Optionally emitting API definitions for
    OpenAPI (Swagger) v2.
  • Setting gRPC timeouts
    through inbound HTTP Grpc-Timeout header.
  • Partial support for gRPC API Configuration
    files as an alternative to annotation.
  • Automatically translating PATCH requests into Field Mask gRPC requests. See
    the docs
    for more information.
  • Protobuf Editions support (edition 2023).
  • Go Opaque API support.

No plan to support

But patches are welcome.

  • Method parameters in HTTP headers.
  • Handling trailer metadata.
  • Encoding request/response body in XML.
  • True bi-directional streaming.

Mapping gRPC to HTTP

  • How gRPC error codes map to HTTP status codes in the response.
  • HTTP request source IP is added as X-Forwarded-For gRPC request header.
  • HTTP request host is added as X-Forwarded-Host gRPC request header.
  • HTTP Authorization header is added as authorization gRPC request header.
  • Remaining Permanent HTTP header keys (as specified by the IANA
    here)
    are prefixed with grpcgateway- and added with their values to gRPC request
    header.
  • HTTP headers that start with 'Grpc-Metadata-' are mapped to gRPC metadata
    (prefixed with grpcgateway-).
  • While configurable, the default {un,}marshaling uses
    protojson.
  • The path template used to map gRPC service methods to HTTP endpoints supports the google.api.http
    path template syntax. For example, /api/v1/{name=projects/*/topics/*} or /prefix/{path=organizations/**}.

Contribution

See CONTRIBUTING.md.

License

gRPC-Gateway is licensed under the BSD 3-Clause License.
See LICENSE for more details.


Overview (`openapiv3-merge/README.md`)

openapiv3-merge

openapiv3-merge combines multiple OpenAPI 3.1 JSON documents into a single
document. It is the companion tool for protoc-gen-openapiv3,
which emits one document per proto file. Pipe its output through
openapiv3-merge to produce a single combined spec.

Why a separate binary

protoc-gen-openapiv3 follows the protobuf convention of one output file per
input file. That keeps the plugin well-behaved under all protoc/buf
invocations and avoids forcing buf users onto strategy: all. The trade-off
is that consumers who want one document have to combine the per-file outputs
themselves. openapiv3-merge is that step.

Install

sh
go install github.com/grpc-ecosystem/grpc-gateway/v2/openapiv3-merge@latest

Usage

sh
openapiv3-merge FILE [FILE ...] > merged.openapi.json

The merged document is written to stdout. Errors go to stderr and the
process exits with a non-zero status. Input order matters: the first
input's info, servers, and externalDocs are kept in the merged
document, so put the file with the broadest scope first.

With buf

sh
#!/usr/bin/env bash
set -euo pipefail

buf generate

# Put the file with the shared openapiv3_document annotation first so
# its info/servers/externalDocs are kept; sort the rest for determinism.
root=gen/api/v1/api.openapi.json
mapfile -t rest < <(find gen -name '*.openapi.json' ! -path "$root" | sort)
openapiv3-merge "$root" "${rest[@]}" > gen/api.openapi.json

With protoc

sh
#!/usr/bin/env bash
set -euo pipefail

protoc -I. \
  --openapiv3_out=./gen \
  $(find . -name '*.proto')

root=gen/api/v1/api.openapi.json
mapfile -t rest < <(find gen -name '*.openapi.json' ! -path "$root" | sort)
openapiv3-merge "$root" "${rest[@]}" > gen/api.openapi.json

One-shot

For trivial trees where any input may go first:

sh
openapiv3-merge $(find . -name '*.openapi.json' | sort) > api.openapi.json

Merge rules

The merger is strict: anything that could be a silent overwrite is rejected.

Field Rule
openapi Must match across all inputs.
info, servers, externalDocs Taken from the first input. Later inputs' values are dropped.
paths, webhooks Unioned in input order. Same path with non-identical content → error.
components/* Unioned with sorted keys. Same name with non-identical content → error.
tags Deduplicated by name. Same name with non-identical metadata → error.
security First input to declare a non-empty array wins. Later inputs that declare a different non-empty array → error.
Unknown top-level keys (extensions, x-*) Taken from the first input.

"Non-identical content" is compared canonically: two values that differ only
in key order are equal. This means component schemas with the same fully
qualified name (which is what protoc-gen-openapiv3 emits — e.g.
example.v1.User) merge cleanly across packages.

Output

  • Top-level fields appear in OpenAPI 3.1.0 declaration order.
  • paths and webhooks are emitted in input order.
  • components/* sub-maps are sorted by key, matching protoc-gen-openapiv3.
  • Tags appear in first-occurrence order.

Overview (`examples/internal/README.md`)

One way to run the example

bash
# Handle dependencies (this repository uses Go modules)
$ go mod download

Follow the guides from this README.md to run the server and gateway.

bash
# Make sure you are in the correct directory: 
# $GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal
$ cd examples/internal/browser
$ pwd

# Install gulp
$ npm install gulp-cli
$ npm install
$ gulp

# Run
$ gulp bower
$ gulp backends

Then you can use curl or a browser to test:

bash
# List all apis
$ curl http://localhost:8080/openapiv2/echo_service.swagger.json

# Visit the apis
$ curl -XPOST http://localhost:8080/v1/example/echo/foo
{"id":"foo"}

$ curl  http://localhost:8080/v1/example/echo/foo/123
{"id":"foo","num":"123"}

So you have visited the apis by HTTP successfully. You can also try other apis.


Overview (`internal/casing/README.md`)

Case conversion

This package contains two functions:

  • Camel copied from the github.com/golang/protobuf/protoc-gen-go/generator package.
  • JSONCamelCase copied from the github.com/protocolbuffers/protobuf-go/internal/strs package.

Both these modules are licensed by The Go Authors, as reflected in this package's [LICENSE.md].


Overview (`examples/internal/browser/README.md`)

Browser example

This directory contains an example use of gRPC-Gateway with web browsers.
The following commands automatically runs integration tests with phantomjs.

shell-session
$ npm install gulp-cli
$ npm install
$ gulp

Other examples

Very simple example

Run

shell-session
$ gulp bower
$ gulp backends

then, open index.html.

Integration test with your browser

Run

shell-session
$ gulp serve

then, open http://localhost:8000 with your browser.


Index (`docs/index.md`)


gRPC-Gateway

{: .fs-9 }

gRPC-Gateway is a plugin of protoc. It reads a gRPC service definition and generates a reverse-proxy server which translates a RESTful JSON API into gRPC. This server is generated according to custom options in your gRPC definition.
{: .fs-6 .fw-300 }

Get started{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 } View it on GitHub{: .btn .fs-5 .mb-4 .mb-md-0 }


Getting started





gRPC-Gateway helps you to provide your APIs in both gRPC and RESTful style at the same time.

To learn more about gRPC-Gateway check out the documentation.

Contribution

See CONTRIBUTING.md.

License

gRPC-Gateway is licensed under the BSD 3-Clause License.

See LICENSE for more details.

Thank you to the contributors of gRPC-Gateway

{% for contributor in site.github.contributors %}

  • []({{ contributor.html_url }})
  • {% endfor %}

    Docs Contributing Index (`docs/docs/contributing/index.md`)


    layout: default title: Contributing nav_order: 5 has_children: true


    Docs Development Index (`docs/docs/development/index.md`)


    layout: default title: Development nav_order: 4 has_children: true


    Docs Mapping Index (`docs/docs/mapping/index.md`)


    layout: default title: Mapping nav_order: 2 has_children: true


    Docs Operations Index (`docs/docs/operations/index.md`)


    layout: default title: Operations nav_order: 3 has_children: true


    Docs Overview Index (`docs/docs/overview/index.md`)


    layout: default title: Overview nav_order: 1 has_children: true


    Docs Tutorials Index (`docs/docs/tutorials/index.md`)


    layout: default title: Tutorials nav_order: 6 has_children: true


    Docs Tutorials Generating Stubs Index (`docs/docs/tutorials/generating_stubs/index.md`)


    layout: default title: Generating stubs parent: Tutorials nav_order: 2 has_children: true

    For generating the stubs, we have two alternatives: protoc and buf. protoc is the more classic generation experience that is used widely in the industry, but it has a pretty steep learning curve. buf is a newer tool that is built with user experience and speed in mind. It also offers linting and breaking change detection, something protoc doesn't offer. We offer instructions for both here.


    Config.Yml (`docs/_config.yml`)

    Site settings

    These are used to personalize your new site. If you look in the HTML files,

    you will see them accessed via {{ site.title }}, {{ site.github_repo }}, and so on.

    You can create any custom variable you would like, and they will be accessible

    in the templates via {{ site.myvariable }}.

    title: gRPC-Gateway
    baseurl: "/grpc-gateway" # the subpath of your site, e.g. /blog
    url: "https://grpc-ecosystem.github.io" # the base hostname & protocol for your site, e.g. http://example.com
    remote_theme: pmarsceill/[email protected]

    permalink: pretty
    exclude: ["run.sh"]

    Set a path/url to a logo that will be displayed instead of the title

    #logo: "/assets/images/grpc-gateway.png"

    Supports true (default) or false

    search_enabled: true
    search:

    Split pages into sections that can be searched individually

    Supports 1 - 6, default: 2

    heading_level: 2

    Maximum amount of previews per search result

    Default: 3

    previews: 2

    Maximum amount of words to display before a matched word in the preview

    Default: 5

    preview_words_before: 3

    Maximum amount of words to display after a matched word in the preview

    Default: 10

    preview_words_after: 3

    Set the search token separator

    Default: /[\s\-/]+/

    Example: enable support for hyphenated search words

    tokenizer_separator: /[\s/]+/

    Display the relative url in search results

    Supports true (default) or false

    rel_url: true

    Enable or disable the search button that appears in the bottom right corner of every page

    Supports true or false (default)

    button: false

    Enable or disable heading anchors

    heading_anchors: true

    aux_links:
    "gRPC-Gateway on GitHub":
    - "https://github.com/grpc-ecosystem/grpc-gateway"

    aux_links_new_tab: false

    nav_sort: case_sensitive # Capital letters sorted before lowercase

    appears at the bottom of every page's main content

    back_to_top: true
    back_to_top_text: "Back to top"

    footer_content: 'Copyright © the gRPC-Gateway Authors. Distributed by a BSD 3-Clause License.'

    last_edit_timestamp: true # show or hide edit time - page must have last_modified_date defined in the frontmatter
    last_edit_time_format: "%b %e %Y at %I:%M %p" # uses ruby's time format: https://ruby-doc.org/stdlib-2.7.0/libdoc/time/rdoc/Time.html

    gh_edit_link: true # show or hide edit this page link
    gh_edit_link_text: "Edit this page on GitHub"
    gh_edit_repository: "https://github.com/grpc-ecosystem/grpc-gateway" # the github URL for your repo
    gh_edit_branch: "main" # the branch that your docs is served from
    gh_edit_source: docs # the source that your files originate from
    gh_edit_view_mode: "tree" # "tree" or "edit" if you want the user to jump into the editor immediately

    Color scheme currently only supports "dark", "light"/nil (default), or a custom scheme that you define

    color_scheme: nil

    Disqus Comments

    disqus:

    Leave shortname blank to disable comments site-wide.

    Enable comments for any post by adding `comments: true` to that post's YAML Front Matter.

    shortname:

    Google Analytics Tracking

    e.g, UA-1234567-89

    ga_tracking:

    ga_tracking_anonymize_ip: true # Use GDPR compliant Google Analytics settings (true/nil by default)

    plugins:

    • jekyll-seo-tag
    • jekyll-include-cache

    kramdown:
    syntax_highlighter_opts:
    block:
    line_numbers: false

    compress_html:
    clippings: all
    comments: all
    endings: all
    startings: []
    blanklines: false
    profile: false

    ignore:

    envs: all


    Docs Faq (`docs/docs/faq.md`)


    layout: default title: FAQ nav_order: 7

    FAQ

    How can I write the annotations which gRPC-Gateway requires?

    The gRPC-Gateway follows the spec of google.api.HttpRule, so first check out the documentation if it is feasible in the spec.

    For situations where annotating the proto file is not an option please reference the documentation on gRPC API Configuration

    See also a past discussion in the grpc-io mailing list.

    I want to support a certain style of HTTP request but the code generated by gRPC-Gateway does not. How can I support this style?

    See the question above at first.

    The gRPC-Gateway is intended to cover 80% of use cases without forcing you to write comprehensive but complicated annotations. So the gateway itself does not always cover all the use cases you have by design. In other words, the gateway automates typical boring boilerplate mapping between gRPC and HTTP/1 communication, but it does not do arbitrarily complex custom mappings for you.

    On the other hand, you can still add whatever you want as a middleware which wraps
    runtime.ServeMux. Since runtime.ServeMux is just a standard http.Handler, you can easily write a custom wrapper of runtime.ServeMux, leveraged with existing third-party libraries in Go (e.g. gateway main.go program).

    My gRPC server is written in (Scala or C++ or Ruby or Haskell etc). Is there a (Scala or C++ or Ruby or Haskell etc) version of gRPC-Gateway?

    As of now, No. But it should not be a big issue because the reverse-proxy which gRPC-Gateway generates usually works as an independent process and communicates with your gRPC server over TCP or a Unix domain sockets (Unix systems only).

    Why are the models in the OpenAPI specification prefixed with the last part of the proto package name?

    The reason to generate the prefixes is that we don't have a guaranteed unique namespace. If two packages produce different Foo messages then we will have trouble.

    Why not strip the prefix?

    When a message is added which happens to conflict with another message (e.g. by importing a message with the same name from a different package) it will break code that is very far away from the code that changed. This is in an effort to adhere to the principle of least astonishment.

    What is the difference between the gRPC-Gateway and grpc-httpjson-transcoding?

    The gRPC-Gateway is a generator that generates a Go implementation of a JSON/HTTP-gRPC reverse proxy based on annotations in your proto file, while the grpc-httpjson-transcoding library doesn't require the generation step, it uses protobuf descriptors as config. It can be used as a component of an existing proxy. Google Cloud Endpoints and the gRPC-JSON transcoder filter in Envoy are using this.

    Behavior differences:

    What is the difference between the gRPC-Gateway and gRPC-web?

    Usage

    In the gRPC-Gateway, we generate a reverse-proxy from the proto file annotations. In the front-end, we call directly through REST APIs. We can generate an OpenAPI v2 specification that may further be used to generate the frontend client from using protoc-gen-openapiv2.

    In gRPC-web, the client code is generated directly from the proto files and can be used in the frontend.

    Performance

    The gRPC-Gateway parses JSON to the protobuf binary format before sending it to the gRPC server. It then has to parse the reply back from the protobuf binary format to JSON again The parsing overhead has a negative impact on performance.

    In gRPC-web, the message is sent in the protobuf binary format already, so there is no additional parsing cost on the proxy side.

    Maintenance

    With the gRPC-Gateway, if your proto file changes, we have to regenerate the gateway reverse proxy code. If you are using the HTTP/JSON interface you probably have to change the front-end too, which means making changes in two places.

    In gRPC-web, regenerating the files from the proto file will automatically update the front-end client.




    Docs Using Custom Query Parser (`docs/docs/using_custom_query_parser.md`)

    Custom Query Parameter Parsing in gRPC-Gateway

    The gRPC-Gateway allows you to customize the way query parameters are parsed and mapped to your gRPC request messages. This can be particularly useful when dealing with nested fields or complex query parameter mappings that are not directly supported by the default behavior.

    Example: Custom Query Parameter Parser for Nested Fields

    Suppose you have a gRPC service definition where you want to map query parameters to a nested message field. Here is how you can achieve this using a custom query parameter parser.

    Protobuf Definition:

    protobuf
    syntax = "proto3";
    
    import "google/api/annotations.proto";
    
    package your.service.v1;
    
    message PageOptions {
      int32 limit = 1;
      int32 page = 2;
    }
    
    message ListStuffRequest {
      string stuff_uuid = 1;
      PageOptions pagination = 2;
    }
    
    message ListStuffResponse {
      repeated string stuff = 1;
    }
    
    service MyService {
      rpc ListStuff(ListStuffRequest) returns (ListStuffResponse) {
        option (google.api.http) = {
          get: "/path/to/{stuff_uuid}/stuff"
        };
      }
    }

    The Problem

    The ListStuffRequest message contains a nested PageOptions message that represents pagination options for the list operation. By default, creating a ServerMux in gRPC-Gateway will be able to parse query parameters for the stuff_uuid and other basic fields (that are not your own custom message). Given that PageOptions is a custom message, and therefore will lead to a nested RequestMessage (the root message), it can only parse query parameters for the PageOptions message if they are in the format url?pagination.limit=x. If your endpoint constraints require query parameters to be in the format url?limit=x, without specifying the full qualified path in the url, you will need to implement a custom parser to map these parameters correctly into the nested PageOptions message.

    Custom Query Parameter Parser

    Create a custom QueryParameterParser to handle the nested PageOptions message.

    go
    package customparser
    
    import (
    	"net/url"
    	"strconv"
    
    	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
    	"google.golang.org/protobuf/proto"
    
    	your_service_v1 "path/to/your/service/v1"
    )
    
    // CustomQueryParameterParser parses query parameters into the appropriate gRPC message fields.
    type CustomQueryParameterParser struct{}
    
    // Parse parses query parameters and populates the appropriate fields in the gRPC request message.
    func (p *CustomQueryParameterParser) Parse(target proto.Message, values url.Values, filter *utilities.DoubleArray) error {
    	switch req := target.(type) {
    	// Different messages/requests can have different parsers, of course
    	case *your_service_v1.ListStuffRequest:
    		return populateListStuffParams(values, req)
    	}
    	
    	return (runtime.DefaultQueryParser{}).Parse(target, values, filter)
    }
    
    // populateListStuffParams populates the ListStuffRequest with query parameters.
    func populateListStuffParams(values url.Values, r *your_service_v1.ListStuffRequest) error {
    	pageOptions := &your_service_v1.PageOptions{}
    	
    	if limit := values.Get("limit"); limit != "" {
    		if parsedLimit, err := strconv.Atoi(limit); err == nil {
    			pageOptions.Limit = int32(parsedLimit)
    		}
    	}
    	if page := values.Get("page"); page != "" {
    		if parsedPage, err := strconv.Atoi(page); err == nil {
    			pageOptions.Page = int32(parsedPage)
    		}
    	}
    
    	r.Pagination = pageOptions
    	return nil
    }

    Integrate Your Custom Query Parameter Parser in gRPC-Gateway Setup

    All you need to do now is update the gRPC-Gateway setup, particularly wherever you are defining the mux server, to use the custom query parameter parser.

    go
    package main
    
    import (
    	"context"
    	"net/http"
    	
    	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    	"google.golang.org/grpc/metadata"
    	"google.golang.org/protobuf/encoding/protojson"
    
    	"your_module/path/customparser"
    )
    
    // create a new ServeMux with custom parser and other runtime options as needed
    func createGRPCGatewayMux() *runtime.ServeMux {
    	// whatever custom code you may need before you create the mux...
    	
    	return runtime.NewServeMux(
    		// Custom query parameter parser
    		runtime.SetQueryParameterParser(&customparser.CustomQueryParameterParser{}),
    		
    		// other runtime options you may need...
    	)
    }

    Docs Contributing 2020 Season Of Docs (`docs/docs/contributing/2020_season_of_docs.md`)


    layout: default title: Google Season of Docs nav_order: 1 parent: Contributing

    2020 Season of Docs

    The gRPC-Gateway participated in the 2020 Google Season of Docs.
    The project was completed by @iamrajiv. A summary of the project
    work can be found in the
    project report.


    Docs Contributing Getting Started (`docs/docs/contributing/getting_started.md`)


    layout: default title: Getting started nav_order: 0 parent: Contributing

    How to contribute

    See CONTRIBUTING.md.


    Docs Development Grpc Gateway V2 Migration Guide (`docs/docs/development/grpc-gateway_v2_migration_guide.md`)


    layout: default title: gRPC-Gateway v2 migration guide nav_order: 0 parent: Development

    gRPC-Gateway v2 migration guide

    This guide is supposed to help users of the gateway migrate from v1 to v2. See the original issue for detailed information on all changes that were made specifically to v2.

    The following behavioural defaults have been changed:

    protoc-gen-swagger has been renamed protoc-gen-openapiv2

    See the original issue
    for more information. Apart from the new name, the only real difference to users will be a slightly different proto annotation:

    protobuf
    import "protoc-gen-openapiv2/options/annotations.proto";

    instead of

    protobuf
    import "protoc-gen-swagger/options/annotations.proto";

    and

    protobuf
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {

    instead of

    protobuf
    option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {

    The Bazel rule has been renamed protoc_gen_openapiv2.

    The example field in the OpenAPI annotations is now a string

    This was a google.protobuf.Any type, but it was only used for the JSON representation, and it was breaking some tools and it was generally unclear to the user how it works. It is now a string instead. The value is copied verbatim to the output OpenAPI file. Remember to escape any quotes in the strings.

    For example, if you had an example that looked like this:

    protobuf
    example: { value: '{ "uuid": "0cf361e1-4b44-483d-a159-54dabdf7e814" }' }

    It would now look like this:

    protobuf
    example: "{\"uuid\": \"0cf361e1-4b44-483d-a159-54dabdf7e814\"}"

    See a_bit_of_everything.proto in the example protos for more examples.

    We now use the camelCase JSON names by default

    See the original issue and
    original pull request for more information.

    If you want to revert to the old behaviour, configure a custom marshaler with UseProtoNames: true:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
    		Marshaler: &runtime.JSONPb{
    			MarshalOptions: protojson.MarshalOptions{
    				UseProtoNames:   true,
    				EmitUnpopulated: true,
    			},
    			UnmarshalOptions: protojson.UnmarshalOptions{
    				DiscardUnknown: true,
    			},
    		},
    	}),
    )

    To change the OpenAPI generator behaviour to match, set json_names_for_fields=false when generating:

    sh
    --openapiv2_out=json_names_for_fields=false:./gen/openapiv2 path/to/my/proto/v1/myproto.proto

    If using the Bazel rule, set json_names_for_fields=False.

    We now emit default values for all fields

    See the original issue
    for more information.

    If you want to revert to the old behaviour, configure a custom marshaler with
    EmitUnpopulated: false:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
    		Marshaler: &runtime.JSONPb{
    			MarshalOptions: protojson.MarshalOptions{
    				EmitUnpopulated: false,
    			},
    			UnmarshalOptions: protojson.UnmarshalOptions{
    				DiscardUnknown: true,
    			},
    		},
    	}),
    )

    We now support google.api.HttpBody message types by default

    The runtime.SetHTTPBodyMarshaler function has disappeared, and is now
    enabled by default. If you for some reason don't want HttpBody messages to be
    respected, you can disable it by overwriting the default marshaler with one which
    does not wrap runtime.JSONPb in runtime.HTTPBodyMarshaler:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
    		MarshalOptions: protojson.MarshalOptions{
    			EmitUnpopulated: true,
    		},
    		UnmarshalOptions: protojson.UnmarshalOptions{
    			DiscardUnknown: true,
    		},
    	}),
    )

    runtime.DisallowUnknownFields has been removed

    All marshalling settings are now inherited from the configured marshaler. If you wish
    to disallow unknown fields, configure a custom marshaler:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
    		Marshaler: &runtime.JSONPb{
    			MarshalOptions: protojson.MarshalOptions{
    				EmitUnpopulated: true,
    			},
    			UnmarshalOptions: protojson.UnmarshalOptions{
    				DiscardUnknown: false,
    			},
    		},
    	}),
    )

    WithLastMatchWins and allow_colon_final_segments=true is now default behaviour

    If you were previously specifying these, please remove them, as this is now
    the default behaviour. See the original issue for more information.

    There is no workaround for this, as we considered it a correct interpretation of the spec. If this breaks your application, carefully consider the order in which you define your services.

    Error handling configuration has been overhauled

    runtime.HTTPError, runtime.OtherErrorHandler, runtime.GlobalHTTPErrorHandler, runtime.WithProtoErrorHandler are all gone. Error handling is rewritten around the use of gRPCs Status types. If you wish to configure how the gateway handles errors, please use runtime.WithErrorHandler and runtime.WithStreamErrorHandler. To handle routing errors (similar to the removed runtime.OtherErrorHandler) please use runtime.WithRoutingErrorHandler.

    Default query parameter parsing behaviour change

    The default behaviour for query parameter parsing has changed to return an InvalidArgument (400 Bad Request) error when more than one of the same matching query parameters is parsed. Previously, it would log but not return an error, using the first query parameter that matched and ignoring any others. See the original issue for more information.


    Docs Development Installation For Cygwin (`docs/docs/development/installation_for_cygwin.md`)


    layout: default title: Installation for Cygwin nav_order: 1 parent: Development

    Installation for Cygwin

    Installation

    First, you need to install the Go language. Please install the latest version, not the one that is listed here.

    text
    wget -N https://storage.googleapis.com/golang/go1.8.1.windows-amd64.msi
    msiexec /i go1.8.1.windows-amd64.msi /passive /promptrestart

    Then you need to install ProtocolBuffers 3.0.0-beta-3 or later. Use the Windows release as no native Cygwin protoc with version 3 is available yet.

    text
    wget -N https://github.com/google/protobuf/releases/download/v3.2.0/protoc-3.2.0-win32.zip`
    7z x protoc-3.2.0-win32.zip -o/usr/local/

    Then you need to set up your Go workspace. Create the workspace dir.

    text
    mkdir /home/user/go
    mkdir /home/user/go/bin
    mkdir /home/user/go/pkg
    mkdir /home/user/go/src

    From an elevated cmd.exe prompt set the GOPATH variable in Windows and add the $GOPATH/bin directory to your path using reg add instead of setx because setx can truncate your PATH variable to 1024 characters.

    text
    setx GOPATH c:\path\to\your\cygwin\home\user\go /M
    set pathkey="HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment"
    for /F "usebackq skip=2 tokens=2*" %A IN (`reg query %pathkey% /v Path`) do (reg add %pathkey% /f /v Path /t REG_SZ /d "%B;c:\path\to\your\cygwin\home\user\go\bin")

    Then go get -u -v the following packages:

    text
    go get -u -v github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
    go get -u -v github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
    go get -u -v google.golang.org/protobuf/cmd/protoc-gen-go
    go get -u -v google.golang.org/grpc/cmd/protoc-gen-go-grpc

    This will probably fail with a similar output to this:

    text
    github.com/grpc-ecosystem/grpc-gateway (download)
    # cd .; git clone https://github.com/grpc-ecosystem/grpc-gateway C:\path\to\your\cygwin\home\user\go\src\github.com\grpc-ecosystem\grpc-gateway
    Cloning into 'C:\path\to\your\cygwin\home\user\go\src\github.com\grpc-ecosystem\grpc-gateway'...
    fatal: Invalid path '/home/user/go/C:\path\to\your\cygwin\home\user\go\src\github.com\grpc-ecosystem\grpc-gateway': No such file or directory
    package github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway: exit status 128

    To fix this you need to run the go get -u -v commands and look for all lines starting with # cd .;. Copy and paste these lines into your shell and change the clone destination directories.

    text
    git clone https://github.com/grpc-ecosystem/grpc-gateway $(cygpath -u $GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway
    git clone https://github.com/golang/protobuf $(cygpath -u $GOPATH)/src/github.com/golang/protobuf
    git clone https://github.com/google/go-genproto $(cygpath -u $GOPATH)/src/google.golang.org/genproto

    Once the clone operations are finished the go get -u -v commands shouldn't give you an error anymore.

    Usage

    Follow the instructions in the README.

    Adjust steps 3, 5 and 7 like this. protoc expects native Windows paths.

    text
    protoc -I. -I$(cygpath -w /usr/local/include) -I${GOPATH}/src --go_out=. --go-grpc_out=. ./path/to/your_service.proto
    protoc -I. -I$(cygpath -w /usr/local/include) -I${GOPATH}/src ./path/to/your_service.proto
    protoc -I. -I$(cygpath -w /usr/local/include) -I${GOPATH}/src ./path/to/your_service.proto

    Then cd into the directory where your entry-point main.go file is located and run:

    text
    go get -v

    This will fail in this same way as it did during the installation. Look for all lines starting with # cd .;. Copy and paste these lines into your shell and change the clone destination directories.

    text
    git clone https://go.googlesource.com/net $(cygpath -u $GOPATH)/src/golang.org/x/net
    git clone https://go.googlesource.com/text $(cygpath -u $GOPATH)/src/golang.org/x/text
    git clone https://github.com/grpc/grpc-go $(cygpath -u $GOPATH)/src/google.golang.org/grpc

    Once the clone operations are finished the go get -v commands shouldn't give you an error anymore.

    Then run:

    text
    go install

    This will compile and install your gRPC-Gateway service into $GOPATH/bin.


    Docs Mapping Binary File Uploads (`docs/docs/mapping/binary_file_uploads.md`)


    layout: default title: Binary file uploads nav_order: 2 parent: Mapping

    Binary file uploads

    If you need to do a binary file upload, e.g. via;

    sh
    curl -X POST -F "attachment=@/tmp/somefile.txt" http://localhost:9090/v1/files

    then your request will contain the binary data directly and there is no way to model this using gRPC.

    What you can do instead is to add a custom route directly on the mux instance.

    Custom route on a mux instance

    Here we'll setup a handler (handleBinaryFileUpload) for POST requests:

    go
    // Create a mux instance
    mux := runtime.NewServeMux()
    
    // Attachment upload from http/s handled manually
    mux.HandlePath("POST", "/v1/files", handleBinaryFileUpload)

    And then in your handler you can do something like:

    go
    func handleBinaryFileUpload(w http.ResponseWriter, r *http.Request, params map[string]string) {
    	err := r.ParseForm()
    	if err != nil {
    		http.Error(w, fmt.Sprintf("failed to parse form: %s", err.Error()), http.StatusBadRequest)
    		return
    	}
    
    	f, header, err := r.FormFile("attachment")
    	if err != nil {
    		http.Error(w, fmt.Sprintf("failed to get file 'attachment': %s", err.Error()), http.StatusBadRequest)
    		return
    	}
    	defer f.Close()
    
    	//
    	// Now do something with the io.Reader in `f`, i.e. read it into a buffer or stream it to a gRPC client side stream.
    	// Also `header` will contain the filename, size etc of the original file.
    	//
    }

    Docs Mapping Custom Marshalers (`docs/docs/mapping/custom_marshalers.md`)


    layout: default title: Custom marshalers nav_order: 6 parent: Mapping

    Custom marshalers

    Marshaler
    implementations can implement optional additional methods to customize their
    behaviour beyond the methods required by the core interface.

    Stream delimiters

    By default, a streamed response delimits each response body with a single
    newline ("\n"). You can change this delimiter by having your marshaler
    implement
    Delimited.

    For example, to separate each entry with a pipe ("|") instead:

    go
    type YourMarshaler struct {
      // ...
    }
    
    // ...
    
    func (*YourMarshaler) Delimiter() []byte {
      return []byte("|")
    }

    Stream content type

    By default, a streamed response emits a Content-Type header that is the same
    for a unary response, from the ContentType() method of the
    Marshaler
    interface.

    If you require the server to declare a distinct content type for stream
    responses versus unary responses, the marshaler must implement
    StreamContentType.
    This provides the MIME type when specifically responding to a streaming
    response.

    For example, by default the
    JSONPb
    marshaler results in application/json for its Content-Type response header,
    irrespective of unary versus streaming. This can be changed for streaming
    endpoints by wrapping the marshaler with a custom marshaler that implements
    StreamContentType
    to return the NDJSON MIME type for
    streaming response endpoints:

    go
    type CustomJSONPb struct {
      runtime.JSONPb
    }
    
    func (*CustomJSONPb) Delimiter() []byte {
      // Strictly speaking this is already the default delimiter for JSONPb, but
      // providing it here for completeness with an NDJSON marshaler all in one
      // place.
      return []byte("\n")
    }
    
    func (*CustomJSONPb) StreamContentType(interface{}) string {
      return "application/x-ndjson"
    }

    Docs Mapping Customizing Openapi Output (`docs/docs/mapping/customizing_openapi_output.md`)


    layout: default title: Customizing OpenAPI Output nav_order: 4 parent: Mapping

    {% raw %}

    Customizing OpenAPI Output

    In proto comments

    You can provide comments directly in your Protocol Buffer definitions and they will be translated into comments in the generated OpenAPI definitions:

    protobuf
    message MyMessage {
      // This comment will end up directly in your Open API definition
      string uuid = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {description: "The UUID field."}];
    }

    You can disable this behavior and exclude all protobuf comments from OpenAPI output via the ignore_comments option.

    Using proto options

    You can define options on your Protocol Buffer services, operations, messages, enums and field definitions to customize your Open API output. For instance, to customize the OpenAPI Schema Object for messages and fields:

    protobuf
    import "protoc-gen-openapiv2/options/annotations.proto";
    
    message ABitOfEverything {
        option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
            json_schema: {
                title: "A bit of everything"
                description: "Intentionally complicated message type to cover many features of Protobuf."
                required: ["uuid", "int64_value", "double_value"]
            }
            external_docs: {
                url: "https://github.com/grpc-ecosystem/grpc-gateway";
                description: "Find out more about ABitOfEverything";
            }
            example: "{\"uuid\": \"0cf361e1-4b44-483d-a159-54dabdf7e814\"}"
            extensions: {
                key: "x-irreversible";
                value {
                    bool_value: true;
                }
            }
        };
    
        string uuid = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {description: "The UUID field."}];
    }

    Enums can be customized like messages:

    protobuf
    // NumericEnum is one or zero.
    enum NumericEnum {
      option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_enum) = {
        description: "NumericEnum is one or zero."
        title: "NumericEnum"
        extensions: {
          key: "x-a-bit-of-everything-foo"
          value {
            string_value: "bar"
          }
        }
        external_docs: {
          url: "https://github.com/grpc-ecosystem/grpc-gateway"
          description: "Find out more about ABitOfEverything"
        }
        example: "\"ZERO\""
      };
      // ZERO means 0
      ZERO = 0;
      // ONE means 1
      ONE = 1;
    }

    Operations can also be customized:

    protobuf
    service ABitOfEverythingService {
       rpc Delete(grpc.gateway.examples.internal.proto.sub2.IdMessage) returns (google.protobuf.Empty) {
            option (google.api.http) = {
                delete: "/v1/example/a_bit_of_everything/{uuid}"
            };
            option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
                security: {
                    security_requirement: {
                        key: "ApiKeyAuth";
                        value: {}
                    }
                    security_requirement: {
                        key: "OAuth2";
                        value: {
                            scope: "read";
                            scope: "write";
                        }
                    }
                }
                extensions: {
                    key: "x-irreversible";
                    value {
                        bool_value: true;
                    }
                }
            };
        }
    }

    Swagger Extensions can be added as key-value pairs to the options. Keys must begin with x- and values can be of any type listed here. For example:

    text
    extensions: {
      key: "x-amazon-apigateway-authorizer";
      value {
        struct_value {
          fields {
            key: "type";
            value {
              string_value: "token";
            }
          }
          fields {
            key: "authorizerResultTtlInSeconds";
            value {
              number_value: 60;
            }
          }
        }
      }
    }

    Please see this a_bit_of_everything.proto for examples of the options being used.

    Using google.api.field_behavior

    Google provides a field option for defining the behavior of fields that is also supported:

    protobuf
    import "google/api/field_behavior.proto";
    
    message MyMessage {
        string a_required_field = 1 [(google.api.field_behavior) = REQUIRED];
    }

    The following options are used in the Open API output:

    • REQUIRED - marks a field as required
    • OUTPUT_ONLY - marks a field as readonly

    Google defines a couple of other options - OPTIONAL, IMMUTABLE, INPUT_ONLY -
    that are not currently used. OPTIONAL support is currently under discussion
    in this issue.

    For IMMUTABLE and INPUT_ONLY fields, there is an open issue in the Open API specification for adding functionality for write-once or immutable fields to the spec.

    Using go templates in proto file comments

    Use Go templates in your proto file comments to allow more advanced documentation such as:

    • Documentation about fields in the proto objects.
    • Import the content of external files (such as
      Markdown).

    How to use it

    By default this function is turned off, so if you want to use it you have to add the use_go_templates option:

    sh
    --openapiv2_out . --openapiv2_opt use_go_templates=true

    or:

    sh
    --openapiv2_out=use_go_templates=true:.

    Example script

    Example of a bash script with the use_go_templates flag set to true:

    sh
    $ protoc -I. \
        --go_out . --go-grpc_out . \
        --grpc-gateway_out . \
        --openapiv2_out . \
        --openapiv2_opt use_go_templates=true \
        path/to/my/proto/v1/myproto.proto

    Example proto file

    Example of a proto file with Go templates. This proto file imports documentation from another file, tables.md:

    protobuf
    service LoginService {
        // Login
        //
        // {{.MethodDescriptorProto.Name}} is a call with the method(s) {{$first := true}}{{range .Bindings}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{.HTTPMethod}}{{end}} within the "{{.Service.Name}}" service.
        // It takes in "{{.RequestType.Name}}" and returns a "{{.ResponseType.Name}}".
        //
        // {{import "tables.md"}}
        rpc Login (LoginRequest) returns (LoginReply) {
            option (google.api.http) = {
                post: "/v1/example/login"
                body: "*"
            };
        }
    }
    
    message LoginRequest {
        // The entered username
        string username = 1;
        // The entered password
        string password = 2;
    }
    
    message LoginReply {
        // Whether you have access or not
        bool access = 1;
    }

    The content of tables.md:

    markdown
    ## {{.RequestType.Name}}
    | Field ID    | Name      | Type                                                       | Description                  |
    | ----------- | --------- | ---------------------------------------------------------  | ---------------------------- | {{range .RequestType.Fields}}
    | {{.Number}} | {{.Name}} | {{if eq .Label.String "LABEL_REPEATED"}}[]{{end}}{{.Type}} | {{fieldcomments .Message .}} | {{end}}
    
    ## {{.ResponseType.Name}}
    | Field ID    | Name      | Type                                                       | Description                  |
    | ----------- | --------- | ---------------------------------------------------------- | ---------------------------- | {{range .ResponseType.Fields}}
    | {{.Number}} | {{.Name}} | {{if eq .Label.String "LABEL_REPEATED"}}[]{{end}}{{.Type}} | {{fieldcomments .Message .}} | {{end}}

    OpenAPI output

    SwaggerUI

    This is how the OpenAPI file would be rendered in Swagger UI.

    Postman

    This is how the OpenAPI file would be rendered in Postman.

    For a more detailed example of a proto file that has Go, templates enabled, see the examples.

    Using custom values

    Custom values can be specified in the Go templates that generate your proto file comments.

    A use case might be to interpolate different external documentation URLs when rendering documentation for different environments.

    How to use it

    The use_go_templates option has to be enabled as a prerequisite.

    Provide customized values in the format of go_template_args=my_key=my_value. {{arg "my_key"}} will be replaced with my_value in the Go template.

    Specify the go_template_args option multiple times if needed.

    sh
    --openapiv2_out . --openapiv2_opt use_go_templates=true --openapiv2_opt go_template_args=my_key1=my_value1 --openapiv2_opt go_template_args=my_key2=my_value2
    ...

    Example script

    Example of a bash script with the use_go_templates flag set to true and custom template values set:

    sh
    $ protoc -I. \
        --go_out . --go-grpc_out . \
        --grpc-gateway_out . \
        --openapiv2_out . \
        --openapiv2_opt use_go_templates=true \
        --openapiv2_opt go_template_args=environment=test1 \
        --openapiv2_opt go_template_args=environment_label=Test1 \
        path/to/my/proto/v1/myproto.proto

    Example proto file

    Example of a proto file with Go templates and custom values:

    protobuf
    service LoginService {
        // Login (Environment: {{arg "environment_label"}})
        //
        // {{.MethodDescriptorProto.Name}} is a call with the method(s) {{$first := true}}{{range .Bindings}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{.HTTPMethod}}{{end}} within the "{{.Service.Name}}" service.
        // It takes in "{{.RequestType.Name}}" and returns a "{{.ResponseType.Name}}".
        // This only works in the {{arg "environment"}} domain.
        //
        rpc Login (LoginRequest) returns (LoginReply) {
            option (google.api.http) = {
                post: "/v1/example/login"
                body: "*"
            };
        }
    }

    Other plugin options

    A comprehensive list of OpenAPI plugin options can be found here. Options can be passed via protoc CLI:

    sh
    --openapiv2_out . --openapiv2_opt bar=baz,color=red

    Or, with buf in buf.gen.yaml:

    yaml
    - name: openapiv2
        out: foo
        opt: bar=baz,color=red

    Merging output

    If your protobuf definitions are spread across multiple files, the OpenAPI plugin will create a file for each .proto input. This may make sense for Go bindings, since they still share a package space, but fragmenting OpenAPI specifications across multiple files changes the schema itself.

    To merge disparate .proto inputs into a single OpenAPI file, use the allow_merge and merge_file_name options.

    opt: allow_merge=true,merge_file_name=foo will result in a single foo.swagger.json. Note that you may need to set
    the generation strategy to all when merging many files:

    yaml
    - name: openapiv2
        out: foo
        strategy: all
        opt: allow_merge=true,merge_file_name=foo

    File-level options of the merged output (such as info, host or tags) are taken from the first input file that has
    an openapiv2_swagger option, either as an annotation or in the openapi_configuration file. File-level options set
    on any other input file are ignored.

    Enums as integers

    To generate enums as integers instead of strings, use enums_as_ints.

    opt: enums_as_ints=true will result in:

    json
    {
        "name": "enumValue",
        "description": " - Example enums",
        "in": "query",
        "required": false,
        "type": "int",
        "enum": [
            0,
            1
        ],
        "default": 0
    },

    Omitting the default value of enums

    If you define enum types with non default value such as declaring 0 value with UNKNOWN and want to omit the default value from generated swagger file, use omit_enum_default_value.
    This option also applies if enums_as_ints option is enalbled to generate enums as integer.

    opt: omit_enum_default_value=true will result in:

    Input Example:

    text
    enum enumValue {
        UNKNOWN = 0;
        FOO = 1;
    }

    Output json:

    json
    {
        "name": "enumValue",
        "description": " - Example enums",
        "in": "query",
        "required": false,
        "type": "string",
        "enum": [
            "FOO"
        ]
    },

    Hiding fields, methods, services and enum values

    If you require internal or unreleased fields and APIs to be hidden from your API documentation, google.api.VisibilityRule annotations can be added to customize where they are generated. Combined with the option visibility_restriction_selectors, overlapping rules will appear in the OpenAPI output.

    visibility_restriction_selectors can be declared multiple times as an option to include multiple visibility restrictions in the output.
    e.g. if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - visibility_restriction_selectors=PREVIEW
          - visibility_restriction_selectors=INTERNAL

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=visibility_restriction_selectors=PREVIEW --openapiv2_opt=visibility_restriction_selectors=INTERNAL ./path/to/file.proto

    Elements without google.api.VisibilityRule annotations will appear as usual in the generated output.

    These restrictions and selectors are completely arbitrary and you can define whatever values or hierarchies you want. In this example we use INTERNAL and PREVIEW, but INTERNAL, ALPHA, BETA, RELEASED, or anything else could be used if you wish.

    Note: Annotations are only supported on Services, Methods, Fields and Enum Values.

    opt: visibility_restriction_selectors=PREVIEW will result in:

    Input Example:

    protobuf
    service Echo {
        rpc EchoInternal(VisibilityRuleSimpleMessage) returns (VisibilityRuleSimpleMessage) {
            option (google.api.method_visibility).restriction = "INTERNAL";
            option (google.api.http) = {
                get: "/v1/example/echo_internal"
            };
        }
        rpc EchoInternalAndPreview(VisibilityRuleSimpleMessage) returns (VisibilityRuleSimpleMessage) {
            option (google.api.method_visibility).restriction = "INTERNAL,PREVIEW";
            option (google.api.http) = {
                get: "/v1/example/echo_internal_and_preview"
            };
        }
    }
    
    message VisibilityRuleSimpleMessage {
         enum VisibilityEnum {
              UNSPECIFIED = 0;
              VISIBLE = 1;
              INTERNAL = 2 [(google.api.value_visibility).restriction = "INTERNAL"];
              PREVIEW = 3 [(google.api.value_visibility).restriction = "INTERNAL,PREVIEW"];
         }
    
         string internal_field = 1 [(google.api.field_visibility).restriction = "INTERNAL"];
         string preview_field = 2 [(google.api.field_visibility).restriction = "INTERNAL,PREVIEW"];
         VisibilityEnum an_enum = 3;
    }

    Output json:

    text
    /* Detailed source-code truncated for AI context efficiency. */

    For a more in depth example see visibility_rule_echo_service.proto and the following output files for different values of visibility_restriction_selectors:

    Path parameters

    When defining HTTP bindings with path parameters that contain multiple path segments, as suggested by the Google AIPs, the path parameter names are numbered to avoid generating duplicate paths in the OpenAPI file.

    For example, consider:

    protobuf
    service LibraryService {
      rpc GetShelf(GetShelfRequest) returns (Shelf) {
        option (google.api.http) = {
          get: "/v1/{name=shelves/*}"
        };
      }
      rpc GetBook(GetBookRequest) returns (Book) {
        option (google.api.http) = {
          get: "/v1/{name=shelves/*/books/*}"
        };
      }
    }
    
    message GetShelfRequest {
      string name = 1;
    }
    
    message GetBookRequest {
      string name = 1;
    }

    This will generate the following paths:

    • /v1/{name}
    • /v1/{name_1}

    To override the path parameter names, annotate the field used as path parameter:

    protobuf
    message GetShelfRequest {
      string name = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {field_configuration: {path_param_name: "shelfName"}}];
    }
    message GetBookRequest {
      string name = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {field_configuration: {path_param_name: "bookName"}}];
    }

    This will instead generate the following paths:

    • /v1/{shelfName}
    • /v1/{bookName}

    Note that path parameters in OpenAPI does not support values with /, as discussed in
    Support for path parameters which can contain slashes #892,
    so tools as Swagger UI will URL encode any / provided as parameter value. A possible workaround for this is to write
    a custom post processor for your OAS file to replace any path parameter with / into multiple parameters.

    Expand path parameters containing sub-path segments

    Alternative to the above, you can enable the expand_slashed_path_patterns compiler option to expand path parameters containing sub-path segments into the URI.

    For example, consider:

    protobuf
    rpc GetBook(GetBookRequest) returns (Book) {
      option (google.api.http) = {
        get: "/v1/{name=publishers/*/books/*}"
      };
    }

    Where the GetBook has a path parameter name with a pattern publishers/*/books/*. When you enable the expand_slashed_path_patterns=true option the path pattern is expanded into the URI and each wildcard in the pattern is transformed into new path parameter. The generated schema for previous protobuf is:

    json
    {
     "/v1/publishers/{publisher}/books/{book}": {
          "get": {
            "parameters": [
              {
                "name": "publisher",
                "in": "path",
                "required": true,
                "type": "string",
              },
              {
                "name": "book",
                "in": "path",
                "required": true,
                "type": "string",
              }
            ]
          }
        }
    }

    The URI is now pretty descriptive and there are two path parameters publisher and book instead of one name. The name of the new parameters is derived from the path segment before the wildcard in the pattern.

    Caveats:

    • the fact that the original name parameter is missing might complicate the usage of the API if you intend to pass in the name parameters from the resources,
    • when the expand_slashed_path_patterns compiler flag is enabled, the path_param_name field annotation is ignored.

    Output format

    By default the output format is JSON, but it is possible to configure it using the output_format option. Allowed values are: json, yaml. The output format will also change the extension of the output files.

    For example, if using buf:

    yaml
    - name: openapiv2
        out: pkg
        opt: output_format=yaml

    Input example:

    protobuf
    syntax = "proto3";
    
    package helloproto.v1;
    option go_package = "helloproto/v1;helloproto";
    
    import "google/api/annotations.proto";
    
    service EchoService {
        rpc Hello(HelloReq) returns (HelloResp) {
            option (google.api.http) = {
                get: "/api/hello"
            };
        }
    }
    
    message HelloReq {
        string name = 1;
    }
    
    message HelloResp {
        string message = 1;
    }

    Output:

    yaml
    swagger: "2.0"
    info:
      title: helloproto/v1/example.proto
      version: version not set
    tags:
    - name: EchoService
    consumes:
    - application/json
    produces:
    - application/json
    paths:
      /api/hello:
        get:
          operationId: EchoService_Hello
          responses:
            "200":
              description: A successful response.
              schema:
                $ref: '#/definitions/v1HelloResp'
            default:
              description: An unexpected error response.
              schema:
                $ref: '#/definitions/rpcStatus'
          parameters:
          - name: name
            in: query
            required: false
            type: string
          tags:
          - EchoService
    definitions:
      protobufAny:
        type: object
        properties:
          '@type':
            type: string
        additionalProperties: {}
      rpcStatus:
        type: object
        properties:
          code:
            type: integer
            format: int32
          message:
            type: string
          details:
            type: array
            items:
              $ref: '#/definitions/protobufAny'
      v1HelloResp:
        type: object
        properties:
          message:
            type: string

    Disable service tag generation

    By default service tags are generated for backend services, but it is possible to disable it using the disable_service_tags option. Allowed values are: true, false.

    For example, if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - disable_service_tags=true

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=disable_service_tags=true ./path/to/file.proto

    Input example:

    protobuf
    syntax = "proto3";
    
    package helloproto.v1;
    option go_package = "helloproto/v1;helloproto";
    
    import "google/api/annotations.proto";
    
    service EchoService {
        rpc Hello(HelloReq) returns (HelloResp) {
            option (google.api.http) = {
                get: "/api/hello"
            };
        }
    }
    
    message HelloReq {
        string name = 1;
    }
    
    message HelloResp {
        string message = 1;
    }

    Output (tags object are not generated):

    yaml
    swagger: "2.0"
    info:
      title: helloproto/v1/example.proto
      version: version not set
    consumes:
      - application/json
    produces:
      - application/json
    paths:
      /api/hello:
        get:
          operationId: EchoService_Hello

    Allow proto files without a go_package option

    By default, protoc-gen-openapiv2 requires every proto file to declare a go_package option, even though the generator never emits Go source and has no real use for the value. Set ignore_go_package_option=true to tolerate proto files that don't declare one — a placeholder import path is synthesized instead of erroring. Note: if generate_x_go_type is also enabled, the synthesized placeholder (not a real Go import path) will appear in the generated x-go-type extension for any file that used this fallback.

    For example, if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - ignore_go_package_option=true

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=ignore_go_package_option=true ./path/to/file.proto

    Disable default responses

    By default a 200 OK response is rendered for each service operation. But it is possible to disable this and explicitly define your service's responses, using the disable_default_responses option. Allowed values are: true, false.

    Note: This does not alter the behavior of the gateway itself and should be coupled with a ForwardResponseWriter when altering status codes, see Controlling HTTP Response Codes.

    For example, if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - disable_default_responses=true

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=disable_default_responses=true ./path/to/file.proto

    Input example:

    protobuf
    syntax = "proto3";
    
    package helloproto.v1;
    
    import "google/api/annotations.proto";
    import "protoc-gen-openapiv2/options/annotations.proto";
    
    option go_package = "helloproto/v1;helloproto";
    
    service EchoService {
      rpc Hello(HelloReq) returns (HelloResp) {
        option (google.api.http) = {get: "/api/hello"};
        option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
          responses: {
            key: "201",
            value: {
              description: "Created";
              schema: {
                json_schema: {ref: ".helloproto.v1.HelloResp"}
              }
            }
          };
        };
      }
    }
    
    message HelloReq {
      string name = 1;
    }
    
    message HelloResp {
      string message = 1;
    }

    Output (default response not generated):

    yaml
    swagger: "2.0"
    info:
      title: helloproto/v1/hello.proto
      version: version not set
    consumes:
      - application/json
    produces:
      - application/json
    paths:
      /api/hello:
        get:
          operationId: EchoService_Hello
          responses:
            "201":
              description: Created
              schema:
                $ref: "#/definitions/v1HelloResp"
          parameters:
            - name: name
              in: query
              required: false
              type: string
    definitions:
      v1HelloResp:
        type: object
        properties:
          message:
            type: string

    Omit array item type when $ref is a sibling

    By default, when generating OpenAPI schemas for array items that reference other definitions, both type: object and $ref properties are included. However, some strict OpenAPI validators enforce the no-$ref-siblings rule, which prohibits having $ref alongside other properties at the same level. To comply with this strict validation, you can use the omit_array_item_type_when_ref_sibling option. When enabled, this option omits the type: object property from array items when a $ref is present, since $ref already implies the type. Allowed values are: true, false.

    Note: This option only affects the generated OpenAPI specification and does not alter the behavior of the gateway itself.

    For example, if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - omit_array_item_type_when_ref_sibling=true

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=omit_array_item_type_when_ref_sibling=true ./path/to/file.proto

    Input example:

    protobuf
    syntax = "proto3";
    
    package example.v1;
    
    import "google/api/annotations.proto";
    
    option go_package = "example/v1;example";
    
    service ExampleService {
      rpc GetItems(GetItemsRequest) returns (GetItemsResponse) {
        option (google.api.http) = {get: "/api/items"};
      }
    }
    
    message GetItemsRequest {}
    
    message GetItemsResponse {
      repeated Item items = 1;
    }
    
    message Item {
      string id = 1;
      string name = 2;
    }

    Output without the option (default behavior):

    yaml
    definitions:
      v1GetItemsResponse:
        type: object
        properties:
          items:
            type: array
            items:
              type: object  # This can violate strict no-$ref-siblings rule
              $ref: "#/definitions/v1Item"
      v1Item:
        type: object
        properties:
          id:
            type: string
          name:
            type: string

    Output with omit_array_item_type_when_ref_sibling=true:

    yaml
    definitions:
      v1GetItemsResponse:
        type: object
        properties:
          items:
            type: array
            items:
              $ref: "#/definitions/v1Item"  # type: object is omitted
      v1Item:
        type: object
        properties:
          id:
            type: string
          name:
            type: string

    Custom HTTP Header Request Parameters

    By default the parameters for each operation are generated from the protocol buffer definition however you can extend the parameters to include extra HTTP headers if required.

    NOTE: These annotations do not alter the behaviour of the gateway and must be coupled with custom header parsing behaviour in the application. Also be aware that adding header parameters can alter the forwards and backwards compatibility of the schema. You must also set a type for your header which can be one of STRING, INTEGER, NUMBER or BOOLEAN.

    protobuf
    syntax = "proto3";
    
    package helloproto.v1;
    
    import "google/api/annotations.proto";
    import "protoc-gen-openapiv2/options/annotations.proto";
    
    option go_package = "helloproto/v1;helloproto";
    
    service EchoService {
      rpc Hello(HelloReq) returns (HelloResp) {
        option (google.api.http) = {get: "/api/hello"};
        option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
          parameters: {
            headers: {
              name: "X-Foo";
              description: "Foo Header";
              type: STRING,
              required: true;
            };
            headers: {
              name: "X-Bar";
              description: "Bar Header";
              type: NUMBER,
            };
          };
        };
      }
    }
    
    message HelloReq {
      string name = 1;
    }
    
    message HelloResp {
      string message = 1;
    }

    Output:

    yaml
    swagger: "2.0"
    info:
      title: helloproto/v1/hello.proto
      version: version not set
    consumes:
      - application/json
    produces:
      - application/json
    paths:
      /api/hello:
        get:
          operationId: Hello
          responses:
            "200":
              description: A successful response.
              schema:
                $ref: "#/definitions/helloproto.v1.HelloResp"
          parameters:
            - name: name
              in: query
              required: false
              type: string
            - name: X-Foo
              description: Foo Header
              in: header
              required: true
              type: string
            - name: X-Bar
              description: Bar Header
              in: header
              required: false
              type: number
    definitions:
      helloproto.v1.HelloResp:
        type: object
        properties:
          message:
            type: string

    Ignore comments

    If you want to exclude all protobuf comments (such as // buf:lint:ignore) from OpenAPI output, use the ignore_comments option. Allowed values are: true, false.

    Note: ignore_comments and use_go_templates are mutually exclusive and cannot be enabled at the same time.

    If you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - ignore_comments=true

    or with protoc:

    sh
    protoc --openapiv2_out=. --openapiv2_opt=ignore_comments=true ./path/to/file.proto

    Removing internal comments

    If you want to remove internal comments from the from OpenAPI output (such as TODO and FIXME directives) you can use the remove_internal_comments option.
    If set to true, this will remove all comment text located between (-- and --) as per AIP 192: Internal comments.

    Preserve RPC Path Order

    By default, generated Swagger files emit paths found in proto files in alphabetical order. If you would like to
    preserve the order of emitted paths to mirror the path order found in proto files, you can use the preserve_rpc_order option. If set to true, this option will ensure path ordering is preserved for Swagger files with both json and yaml formats.

    This option will also ensure path ordering is preserved in the following scenarios:

    1. When using additional bindings, paths will preserve their ordering within an RPC.
    2. When using multiple services, paths will preserve their ordering between RPCs in the whole protobuf file.
    3. When merging protobuf files, paths will preserve their ordering depending on the order of files specified on the command line.

    preserve_rpc_order can be passed via the protoc CLI:

    sh
    protoc --openapiv2_out=. --openapiv2_opt=preserve_rpc_order=true ./path/to/file.proto

    Or, with buf in buf.gen.yaml:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - preserve_rpc_order=true

    Enable RPC deprecation

    With enable_rpc_deprecation option you can deprecate openapi method using standard method's option. Allowed values are: true, false.

    For example, if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - enable_rpc_deprecation=true

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=enable_rpc_deprecation=true ./path/to/file.proto

    Input example:

    protobuf
    syntax = "proto3";
    
    package helloproto.v1;
    
    import "google/api/annotations.proto";
    
    option go_package = "helloproto/v1;helloproto";
    
    service EchoService {
      rpc Hello(HelloReq) returns (HelloResp) {
        option deprecated = true;
        option (google.api.http) = {get: "/api/hello"};
      }
    }
    
    message HelloReq {
      string name = 1;
    }
    
    message HelloResp {
      string message = 1;
    }

    Output:

    yaml
    swagger: "2.0"
    info:
      title: helloproto/v1/example.proto
      version: version not set
    tags:
      - name: EchoService
    consumes:
      - application/json
    produces:
      - application/json
    paths:
      /api/hello:
        get:
          operationId: EchoService_Hello
          responses:
            "200":
              description: A successful response.
              schema:
                $ref: '#/definitions/v1HelloResp'
            default:
              description: An unexpected error response.
              schema:
                $ref: '#/definitions/rpcStatus'
          parameters:
            - name: name
              in: query
              required: false
              type: string
          tags:
            - EchoService
          deprecated: true
    definitions:
      protobufAny:
        type: object
        properties:
          '@type':
            type: string
        additionalProperties: {}
      rpcStatus:
        type: object
        properties:
          code:
            type: integer
            format: int32
          message:
            type: string
          details:
            type: array
            items:
              type: object
              $ref: '#/definitions/protobufAny'
      v1HelloResp:
        type: object
        properties:
          message:
            type: string

    Deprecating parameters

    With the enable_field_deprecation option, OpenAPI parameters will be marked as deprecated based on the protobuf deprecated field option. Allowed values are: true, false.

    For example, if you are using buf:

    yaml
    version: v1
    plugins:
      - name: openapiv2
        out: .
        opt:
          - enable_field_deprecation=true

    or with protoc

    sh
    protoc --openapiv2_out=. --openapiv2_opt=enable_field_deprecation=true ./path/to/file.proto

    Input example:

    protobuf
    message SearchRequest {
      string legacy_filter = 1 [deprecated = true];
      string query = 2;
    }

    Output (excerpt):

    yaml
    paths:
      /v1/search:
        get:
          parameters:
            - name: legacy_filter
              in: query
              required: false
              type: string
              deprecated: true
            - name: query
              in: query
              required: false
              type: string

    If you prefer to leave the protobuf definition active, you can use the field_configuration.deprecated annotation on the openapiv2_field option instead:

    protobuf
    message SearchRequest {
      string legacy_filter = 1 [
        (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
          description: "Legacy filter syntax. Prefer the new 'query' field."
          field_configuration: { deprecated: true }
        }
      ];
      string query = 2;
    }

    This keeps the protobuf field untouched but still emits a deprecated parameter in the generated spec:

    yaml
    paths:
      /v1/search:
        get:
          parameters:
            - name: legacy_filter
              in: query
              required: false
              type: string
              description: Legacy filter syntax. Prefer the new 'query' field.
              deprecated: true
            - name: query
              in: query
              required: false
              type: string

    If you set both the protobuf deprecated = true option and field_configuration.deprecated, the OpenAPI parameter is marked as deprecated regardless of the enable_field_deprecation option.

    {% endraw %}


    Docs Mapping Customizing Your Gateway (`docs/docs/mapping/customizing_your_gateway.md`)


    layout: default title: Customizing your gateway nav_order: 5 parent: Mapping

    Customizing your gateway

    Message serialization

    Custom serializer

    You might want to serialize request/response messages in MessagePack instead of JSON, for example:

    1. Write a custom implementation of
      Marshaler.
      See Custom marshalers for some additional
      customization options.

    2. Register your marshaler with WithMarshalerOption.

      e.g.

      go
      var m your.MsgPackMarshaler
      mux := runtime.NewServeMux(
          runtime.WithMarshalerOption("application/x-msgpack", m),
      )

    You can see the default implementation for JSON for reference.

    Using proto names in JSON

    The protocol buffer compiler generates camelCase JSON tags that are used by default.
    If you want to use the exact case used in the proto files, set UseProtoNames: true:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
    		MarshalOptions: protojson.MarshalOptions{
    			UseProtoNames: true,
    		},
    		UnmarshalOptions: protojson.UnmarshalOptions{
    			DiscardUnknown: true,
    		},
    	}),
    )

    Pretty-print JSON responses when queried with ?pretty

    You can have Elasticsearch-style ?pretty support in your gateway's endpoints as follows:

    1. Wrap the ServeMux using a stdlib http.HandlerFunc that translates the provided query parameter into a custom Accept header.

    2. Register a pretty-printing marshaler for that MIME code.

    For example:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption("application/json+pretty", &runtime.JSONPb{
    		MarshalOptions: protojson.MarshalOptions{
    			Indent: "  ",
    			Multiline: true, // Optional, implied by presence of "Indent".
    		},
    		UnmarshalOptions: protojson.UnmarshalOptions{
    			DiscardUnknown: true,
    		},
    	}),
    )
    prettier := func(h http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		// checking Values as map[string][]string also catches ?pretty and ?pretty=
    		// r.URL.Query().Get("pretty") would not.
    		if _, ok := r.URL.Query()["pretty"]; ok {
    			r.Header.Set("Accept", "application/json+pretty")
    		}
    		h.ServeHTTP(w, r)
    	})
    }
    http.ListenAndServe(":8080", prettier(mux))

    Now, either when passing the header Accept: application/json+pretty or appending ?pretty to your HTTP endpoints, the response will be pretty-printed.

    Note that this will conflict with any methods having input messages with fields named pretty; also, this example code does not remove the query parameter pretty from further processing.

    Customize unmarshaling per Content-Type

    Having different unmarshaling options per Content-Type is as easy as configuring a custom marshaler:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption("application/json+strict", &runtime.JSONPb{
    		UnmarshalOptions: &protojson.UnmarshalOptions{
    			DiscardUnknown: false, // explicit "false", &protojson.UnmarshalOptions{} would have the same effect
    		},
    	}),
    )

    Note: The incoming Authorization HTTP header can not be removed or overwritten. It will always be forwarded in the gRPC metadata under the authorization key. However, values can be appended.

    Mapping from HTTP request headers to gRPC client metadata

    You might not like the default mapping rule and might want to pass through all the HTTP headers, for example:

    1. Write a HeaderMatcherFunc.

    2. Register the function with WithIncomingHeaderMatcher

      e.g.

      go
      func CustomMatcher(key string) (string, bool) {
          switch key {
          case "X-Custom-Header1":
              return key, true
          case "X-Custom-Header2":
              return "custom-header2", true
          default:
              return key, false
          }
      }
      
      mux := runtime.NewServeMux(
          runtime.WithIncomingHeaderMatcher(CustomMatcher),
      )

    To keep the default mapping rule alongside with your own rules write:

    go
    func CustomMatcher(key string) (string, bool) {
    	switch key {
    	case "X-User-Id":
    		return key, true
    	default:
    		return runtime.DefaultHeaderMatcher(key)
    	}
    }

    It will work with both:

    sh
    $ curl --header "x-user-id: 100d9f38-2777-4ee2-ac3b-b3a108f81a30" ...

    and

    sh
    $ curl --header "X-USER-ID: 100d9f38-2777-4ee2-ac3b-b3a108f81a30" ...

    To access this header on gRPC server side use:

    go
    userID := ""
    if md, ok := metadata.FromIncomingContext(ctx); ok {
    	if uID, ok := md["x-user-id"]; ok {
    		userID = strings.Join(uID, ",")
    	}
    }

    Mapping from gRPC server metadata to HTTP response headers

    Use WithOutgoingHeaderMatcher. See gRPC metadata docs for more info on sending / receiving gRPC metadata, for example:

    go
    if appendCustomHeader {
    	grpc.SendHeader(ctx, metadata.New(map[string]string{
    		"x-custom-header1": "value",
    	}))
    }

    Mutate response messages or set response headers

    Set HTTP headers

    You might want to return a subset of response fields as HTTP response headers; You might want to simply set an application-specific token in a header. Or you might want to mutate the response messages to be returned.

    1. Write a filter function.
    go
    func myFilter(ctx context.Context, w http.ResponseWriter, resp proto.Message) error {
    	t, ok := resp.(*externalpb.Tokenizer)
    	if ok {
    		w.Header().Set("X-My-Tracking-Token", t.Token)
    		t.Token = ""
    	}
    	return nil
    }
    1. Register the filter with WithForwardResponseOption

    e.g.

    go
    mux := runtime.NewServeMux(
    	runtime.WithForwardResponseOption(myFilter),
    )

    Controlling HTTP response status codes

    To have the most control over the HTTP response status codes, you can use custom metadata.

    While handling the rpc, set the intended status code:

    go
    _ = grpc.SetHeader(ctx, metadata.Pairs("x-http-code", "401"))

    Now, before sending the HTTP response, we need to check for this metadata pair and explicitly set the status code for the response if found.
    To do so, create a function and hook it into the gRPC-Gateway as a Forward Response Option.

    The function looks like this:

    go
    func httpResponseModifier(ctx context.Context, w http.ResponseWriter, p proto.Message) error {
    	md, ok := runtime.ServerMetadataFromContext(ctx)
    	if !ok {
    		return nil
    	}
    
    	// set http status code
    	if vals := md.HeaderMD.Get("x-http-code"); len(vals) > 0 {
    		code, err := strconv.Atoi(vals[0])
    		if err != nil {
    			return err
    		}
    		// delete the headers to not expose any grpc-metadata in http response
    		delete(md.HeaderMD, "x-http-code")
    		delete(w.Header(), "Grpc-Metadata-X-Http-Code")
    		w.WriteHeader(code)
    	}
    
    	return nil
    }

    And it gets hooked into the gRPC-Gateway with:

    go
    gwMux := runtime.NewServeMux(
    	runtime.WithForwardResponseOption(httpResponseModifier),
    )

    Additional responses can be added to the Protocol Buffer definitions to match the new status codes:

    protobuf
    service Greeter {
      rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          post: "/v1/example/echo"
          body: "*"
        };
        option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
          responses: {
            key: "201"
            value: {
              description: "A successful response."
              schema: {
                json_schema: {
                  ref: ".mypackage.HelloReply"
                }
              }
            }
          }
        };
      }
    
      rpc SayGoodbye (GoodbyeRequest) returns (google.protobuf.Empty) {
        option (google.api.http) = {
          delete: "/v1/example/echo/{id}"
        };
        option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
          responses: {
            key: "204"
            value: {
              description: "A successful response."
              schema: {}
            }
          }
        };
      }
    }

    Fully Overriding Custom HTTP Responses

    To fully override custom HTTP responses, you can use both a Forward Response Option and a Custom Marshaler.

    For example with proto response message as:

    proto
    message CreateUserResponse {
      string name = 1;
    }

    The default HTTP response:

    json5
    HTTP 200 OK
    Content-Type: application/json
    
    {"name":"John Doe"}

    But you want to return a 201 Created status code along with a custom response structure:

    json5
    HTTP 201 Created
    Content-Type: application/json
    
    {"success":true,"data":{"name":"John Doe"}}

    First, set up the gRPC-Gateway with the custom options:

    go
    mux := runtime.NewServeMux(
      runtime.WithForwardResponseOption(setStatus),
      runtime.WithForwardResponseRewriter(responseEnvelope),
    )

    Define the setStatus function to handle specific response types:

    go
    func setStatus(ctx context.Context, w http.ResponseWriter, m protoreflect.ProtoMessage) error {
      switch v := m.(type) {
      case *pb.CreateUserResponse:
        w.WriteHeader(http.StatusCreated)
      }
      // keep default behavior
      return nil
    }

    Define the responseEnvelope function to rewrite the response to a different type/shape:

    go
    func responseEnvelope(_ context.Context, response proto.Message) (interface{}, error) {
      switch v := response.(type) {
      case *pb.CreateUserResponse:
        // wrap the response in a custom structure
        return map[string]any{
          "success": true,
          "data":    response,
        }, nil
      }
      return response, nil
    }

    In this setup:

    • The setStatus function intercepts the response and uses its type to send 201 Created only when it sees *pb.CreateUserResponse.
    • The responseEnvelope function ensures that specific types of responses are wrapped in a custom structure before being sent to the client.

    ❗ NOTE: Using WithForwardResponseRewriter is partially incompatible with OpenAPI annotations. Because response
    rewriting happens at runtime, it is not possible to represent that in protoc-gen-openapiv2 output.

    Error handler

    To override error handling for a *runtime.ServeMux, use the
    runtime.WithErrorHandler option. This will configure all unary error
    responses to pass through this error handler.

    Stream Error Handler

    The error handler described in the previous section applies only to RPC methods that have a unary response.

    When the method has a streaming response, gRPC-Gateway handles that by emitting a newline-separated stream of "chunks". Each chunk is an envelope that can contain either a response message or an error. Only the last chunk will include an error, and only when the RPC handler ends abnormally (i.e. with an error code).

    Because of the way the errors are included in the response body, the other error handler signature is insufficient. So for server streams, you must install a different error handler:

    go
    mux := runtime.NewServeMux(
    	runtime.WithStreamErrorHandler(handleStreamError),
    )

    The signature of the handler is much more rigid because we need to know the structure of the error payload to properly encode the "chunk" schema into an OpenAPI spec.

    So the function must return a *runtime.StreamError. The handler can choose to omit some fields and can filter/transform the original error, such as stripping stack traces from error messages.

    Here's an example custom handler:

    go
    // handleStreamError overrides default behavior for computing an error
    // message for a server stream.
    //
    // It uses a default "502 Bad Gateway" HTTP code, only emits "safe"
    // messages and does not set the details field (so it will
    // be omitted from the resulting JSON object that is sent to client).
    func handleStreamError(ctx context.Context, err error) *status.Status {
    	code := codes.Internal
    	msg := "unexpected error"
    	if s, ok := status.FromError(err); ok {
    		code = s.Code()
    		// default message, based on the gRPC status
    		msg = s.Message()
    		// see if error details include "safe" message to send
    		// to external callers
    		for _, msg := range s.Details() {
    			if safe, ok := msg.(*SafeMessage); ok {
    				msg = safe.Text
    				break
    			}
    		}
    	}
    	return status.Errorf(code, msg)
    }

    If no custom handler is provided, the default stream error handler will include any gRPC error attributes (code, message, detail messages), if the error being reported includes them. If the error does not have these attributes, a gRPC code of Unknown (2) is reported.

    Controlling path parameter unescaping

    By default, gRPC-Gateway unescapes the entire URL path string attempting to route a request. This causes routing errors when the path parameter contains an illegal character such as /.

    To replicate the behavior described in google.api.http, use runtime.WithUnescapingMode() to configure the unescaping behavior, as in the example below:

    go
    mux := runtime.NewServeMux(
    	runtime.WithUnescapingMode(runtime.UnescapingModeAllExceptReserved),
    )

    For multi-segment parameters (e.g. {id=**}) RFC 6570 Reserved Expansion characters are left escaped and the gRPC API will need to unescape them.

    To replicate the default V2 escaping behavior but also allow passing pct-encoded / characters, the ServeMux can be configured as in the example below:

    go
    mux := runtime.NewServeMux(
    	runtime.WithUnescapingMode(runtime.UnescapingModeAllCharacters),
    )

    Routing Error handler

    To override the error behavior when *runtime.ServeMux was not able to serve the request due to routing issues, use the runtime.WithRoutingErrorHandler option.

    This will configure all HTTP routing errors to pass through this error handler. The default behavior is to map HTTP error codes to gRPC errors.

    HTTP statuses and their mappings to gRPC statuses:

    • HTTP 404 Not Found -> gRPC 5 NOT_FOUND
    • HTTP 405 Method Not Allowed -> gRPC 12 UNIMPLEMENTED
    • HTTP 400 Bad Request -> gRPC 3 INVALID_ARGUMENT

    This method is not used outside of the initial routing.

    Customizing Routing Errors

    If you want to retain HTTP 405 Method Not Allowed instead of allowing it to be converted to the equivalent of the gRPC 12 UNIMPLEMENTED, which is HTTP 501 Not Implemented you can use the following example:

    go
    func handleRoutingError(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, r *http.Request, httpStatus int) {
    	if httpStatus != http.StatusMethodNotAllowed {
    		runtime.DefaultRoutingErrorHandler(ctx, mux, marshaler, w, r, httpStatus)
    		return
    	}
    
    	// Use HTTPStatusError to customize the DefaultHTTPErrorHandler status code
    	err := &runtime.HTTPStatusError{
    		HTTPStatus: httpStatus,
    		Err:        status.Error(codes.Unimplemented, http.StatusText(httpStatus)),
    	}
    
    	runtime.DefaultHTTPErrorHandler(ctx, mux, marshaler, w, r, err)
    }

    To use this routing error handler, construct the mux as follows:

    go
    mux := runtime.NewServeMux(
    	runtime.WithRoutingErrorHandler(handleRoutingError),
    )

    Disabling X-HTTP-Method-Override

    By default, the gRPC-Gateway allows clients to send a POST request with an
    X-HTTP-Method-Override header to override the HTTP method. For example, a
    POST request with X-HTTP-Method-Override: GET will be routed as if it were
    a GET request. This is part of the path length fallback behavior, which
    allows HTML forms (which only support GET and POST) to call other methods.

    This can lead to HTTP method confusion when your gateway sits behind a Web
    Application Firewall (WAF) or reverse proxy that enforces method-based access
    controls. For example, if a WAF is configured to only allow POST requests to
    a particular endpoint, a client could send a POST with
    X-HTTP-Method-Override: DELETE and the gateway would route the request to the
    DELETE handler, bypassing the WAF's intended restrictions. The WAF sees a
    POST request, but the gateway processes it as a DELETE.

    To disable the X-HTTP-Method-Override header handling, use the
    WithDisableHTTPMethodOverride option:

    go
    mux := runtime.NewServeMux(
    	runtime.WithDisableHTTPMethodOverride(),
    )

    This disables only the method override header. The path length fallback (routing
    a POST with Content-Type: application/x-www-form-urlencoded to a matching
    GET handler) remains available unless separately disabled with
    WithDisablePathLengthFallback.


    Docs Mapping Examples (`docs/docs/mapping/examples.md`)


    layout: default title: Examples nav_order: 0 parent: Mapping

    Examples

    Examples are available under examples/internal directory.

    To use the same port for custom HTTP handlers (e.g. serving swagger.json),
    gRPC-Gateway, and a gRPC server, see this code example by CoreOS (and its accompanying
    blog post).


    Docs Mapping Grpc Api Configuration (`docs/docs/mapping/grpc_api_configuration.md`)


    layout: default title: gRPC API Configuration nav_order: 3 parent: Mapping

    gRPC API Configuration

    In some situations annotating the proto file of service is not an option. For example, you might not have control over the proto file, or you might want to expose the same gRPC API multiple times in completely different ways.

    gRPC-Gateway supports 2 ways of dealing with these situations:

    `generate_unbound_methods`

    Providing this parameter to the protoc plugin will make it produce the HTTP mapping even for methods without any HttpRule annotation. This is similar to how Cloud Endpoints behaves and uses the way gRPC itself maps to HTTP/2:

    • HTTP method is POST
    • URI path is built from the service's name and method: /<fully qualified service name>/<method name> (e.g.: /my.package.EchoService/Echo)
    • HTTP body is the serialized protobuf message.

    NOTE: the same option is also supported by the gen-openapiv2 plugin.

    `strict_deep_wildcard`

    By default a deep wildcard (**) that follows another path segment may match zero path segments, so /v3/files/{path=**} also matches /v3/files with an empty path. Providing strict_deep_wildcard=true to the protoc-gen-grpc-gateway plugin makes such patterns require at least one remaining path segment, so /v3/files no longer matches and can be routed to a separately registered /v3/files handler. A request with a trailing slash (/v3/files/) still matches with an empty capture, and a bare ** with nothing before it still matches zero segments.

    sh
    protoc --grpc-gateway_out=. --grpc-gateway_opt=strict_deep_wildcard=true ...

    The generated code requires a version of the runtime package that includes runtime.NewPatternWithOptions.

    Using an external configuration file

    Google Cloud Platform offers a way to do this for services
    hosted with them called "gRPC API Configuration". It can be used to define the behavior of a gRPC API service without modifications to the service itself in the form of YAML configuration files.

    gRPC-Gateway generators implement the HTTP rules part of this specification. This allows you to take a completely unannotated service proto file, add a YAML file describing its HTTP endpoints and use them together like an annotated proto file with the gRPC-Gateway generators.

    OpenAPI options may also be configured via "OpenAPI Configuration" in the form of YAML configuration files.

    Usage of gRPC API Configuration YAML files

    The following is equivalent to the basic README.md example but without direct
    annotation for gRPC-Gateway in the proto file. Only some steps require minor changes to use a gRPC API Configuration YAML file instead:

    1. Define your service in gRPC as usual

      your_service.proto:

      protobuf
      syntax = "proto3";
      package your.service.v1;
      option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1";
      message StringMessage {
        string value = 1;
      }
      
      service YourService {
        rpc Echo(StringMessage) returns (StringMessage) {}
      }
    2. Instead of annotating the proto file in this step leave it untouched
      and create a your_service.yaml with the following content:

      yaml
      type: google.api.Service
      config_version: 3
      
      http:
        rules:
          - selector: your.service.v1.YourService.Echo
            post: /v1/example/echo
            body: "*"

      Use a linter to validate your YAML.

    3. Generate gRPC stub as before

      sh
      protoc -I . \
        --go_out ./gen/go/ \
        --go_opt paths=source_relative \
        --go-grpc_out ./gen/go/ \
        --go-grpc_opt paths=source_relative \
        your/service/v1/your_service.proto

    It will generate a stub file with path ./gen/go/your/service/v1/your_service.pb.go.

    1. Implement your service in gRPC as usual

    2. Generate the reverse-proxy. Here we have to pass the path to
      the your_service.yaml in addition to the proto file:

      sh
      protoc -I . \
        --grpc-gateway_out ./gen/go \
        --grpc-gateway_opt paths=source_relative \
        --grpc-gateway_opt grpc_api_configuration=path/to/your_service.yaml \
        your/service/v1/your_service.proto

      This will generate a reverse proxy gen/go/your/service/v1/your_service.pb.gw.go that is identical to the one produced for the annotated proto.

      Using Buf with one configuration for multiple services

      When a single gRPC API Configuration YAML file contains selectors for
      services defined in different directories, set strategy: all for each
      local Buf plugin that uses the configuration. Buf invokes local plugins
      once per directory by default, so each invocation sees only part of the
      schema and reports rules for services in other directories as unmatched.

      yaml
      version: v2
      plugins:
        - local: protoc-gen-grpc-gateway
          out: gen/go
          strategy: all
          opt:
            - paths=source_relative
            - grpc_api_configuration=path/to/your_service.yaml
        - local: protoc-gen-openapiv2
          out: gen/openapiv2
          strategy: all
          opt:
            - grpc_api_configuration=path/to/your_service.yaml

      See Buf's invocation strategy documentation.

      In situations where you only need the reverse-proxy you can use the standalone=true option when generating the code. This will ensure the types used within your_service.pb.gw.go reference the external source appropriately.

      text
      protoc -I . \
        --grpc-gateway_out ./gen/go \
        --grpc-gateway_opt paths=source_relative \
        --grpc-gateway_opt standalone=true \
        --grpc-gateway_opt grpc_api_configuration=path/to/your_service.yaml \
        your/service/v1/your_service.proto
    3. Generate the optional your_service.swagger.json

      sh
      protoc -I . --openapiv2_out ./gen/go \
        --openapiv2_opt grpc_api_configuration=path/to/your_service.yaml \
        your/service/v1/your_service.proto

      or using an OpenAPI configuration file

      sh
      protoc -I . --openapiv2_out ./gen/go \
        --openapiv2_opt grpc_api_configuration=path/to/your_service.yaml \
        --openapiv2_opt openapi_configuration=path/to/your_service_swagger.yaml \
        your/service/v1/your_service.proto

      For an example of an OpenAPI configuration file, see unannotated_echo_service.swagger.yaml, which adds OpenAPI options to unannotated_echo_service.proto.

      sh
      protoc -I . --openapiv2_out ./gen/go \
        --openapiv2_opt grpc_api_configuration=path/to/your_service.yaml \
        your/service/v1/your_service.proto

    All other steps work as before. If you want you can remove the googleapis include path in step 3 and 4 as the unannotated proto no longer requires them.


    Docs Mapping Httpbody Messages (`docs/docs/mapping/httpbody_messages.md`)


    layout: default title: HttpBody Messages nav_order: 1 parent: Mapping

    HttpBody Messages

    The HTTPBody messages allow a response message to be specified with custom data content and a custom content-type header. The values included in the HTTPBody response will be used verbatim in the returned message from the gateway. Make sure you format your response carefully!

    google.api.HttpBody is also the native gRPC-Gateway response shape to use for
    binary downloads and other raw payload responses where you need to control the
    returned content type directly.

    Example Usage

    1. Define your service in gRPC with an HttpBody response message.
    protobuf
    import "google/api/httpbody.proto";
    import "google/api/annotations.proto";
    import "google/protobuf/empty.proto";
    
    service HttpBodyExampleService {
    	rpc HelloWorld(google.protobuf.Empty) returns (google.api.HttpBody) {
    		option (google.api.http) = {
    			get: "/helloworld"
    		};
    	}
    	rpc Download(google.protobuf.Empty) returns (stream google.api.HttpBody) {
    		option (google.api.http) = {
    			get: "/download"
    		};
    	}
    }
    1. Generate gRPC and reverse-proxy stubs and implement your service.

    Example service implementation

    go
    func (*HttpBodyExampleService) Helloworld(ctx context.Context, in *empty.Empty) (*httpbody.HttpBody, error) {
    	return &httpbody.HttpBody{
    		ContentType: "text/html",
    		Data:        []byte("Hello World"),
    	}, nil
    }
    
    func (HttpBodyExampleService) Download(_ *empty.Empty, stream HttpBodyExampleService_DownloadServer) error {
    	msgs := []*httpbody.HttpBody{
    		{
    			ContentType: "text/html",
    			Data:        []byte("Hello 1"),
    		},
    		{
    			ContentType: "text/html",
    			Data:        []byte("Hello 2"),
    		},
    	}
    
    	for _, msg := range msgs {
    		if err := stream.Send(msg); err != nil {
    			return err
    		}
    	}
    
    	return nil
    }

    Docs Mapping Openapi V3 (`docs/docs/mapping/openapi_v3.md`)


    layout: default title: OpenAPI 3.1 Output nav_order: 7 parent: Mapping

    OpenAPI 3.1 Output

    {: .warning }
    Alpha — output is not yet stable. protoc-gen-openapiv3 is a new
    generator and the exact JSON shape it emits may change between minor
    releases as the mapping rules settle in response to user feedback.
    Specifically expect the encodings for oneofs, wrapper types, enums, and
    path-template expansion to evolve, and expect tooling-compatibility
    compromises (documented inline in the generator source) to be revisited
    as consumer OpenAPI 3.1 support matures. If you need a production-stable
    OpenAPI pipeline today, use protoc-gen-openapiv2.

    {: .note }
    protoc-gen-openapiv3 emits OpenAPI 3.1.0 JSON directly from
    google.api.http annotations. It is intentionally smaller in scope than
    protoc-gen-openapiv2 and does not
    consume the grpc.gateway.protoc_gen_openapiv2.options annotations. If
    you rely on those options, continue to use the v2 generator.

    What it does

    protoc-gen-openapiv3 walks every proto file it is asked to generate, finds
    services with HTTP bindings, and emits one OpenAPI 3.1.0 JSON document per
    proto file
    (foo.proto → foo.openapi.json). Files with no HTTP-bound
    services produce no output.

    The output is deterministic and byte-stable across runs: paths are emitted in
    RPC declaration order, component schemas are sorted alphabetically, and
    response codes are emitted default-first then sorted.

    What it does not do

    The generator is deliberately opinionated. The following are not supported today:

    • The grpc.gateway.protoc_gen_openapiv2.options annotation set.
    • OpenAPI 2.0 / Swagger output (use protoc-gen-openapiv2 for that).
    • YAML output.
    • Alternative naming strategies. Component names are always the
      fully-qualified proto name with the leading dot stripped
      (e.g. lib.v1.Book).
    • Integer enums. Enums are always rendered as strings.

    Features can be added back as concrete needs emerge — if you want one of the
    above, please open an issue describing your use case.

    Plugin options

    `disable_default_errors`

    By default, every operation gets an auto-injected default response entry
    pointing to the google.rpc.Status component schema. If you use a custom
    error handler that returns a different response shape, you can suppress this
    behaviour with the disable_default_errors option.

    With buf (buf.gen.yaml):

    yaml
    version: v2
    plugins:
      - local: protoc-gen-openapiv3
        out: .
        opt:
          - disable_default_errors=true

    With protoc:

    sh
    protoc -I. \
      --openapiv3_out=. \
      --openapiv3_opt=disable_default_errors=true \
      path/to/your/service.proto

    When set, neither the default response entry nor the google.rpc.Status
    component schema are emitted.

    `visibility_restriction_selectors`

    See Hiding fields, methods, services and enum values below.

    Installation

    sh
    go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv3@latest

    Usage with buf

    Add the plugin to your buf.gen.yaml:

    yaml
    version: v2
    plugins:
      - local: protoc-gen-openapiv3
        out: .

    Then run buf generate as usual. A .openapi.json file will appear next to
    each proto file that declares HTTP bindings.

    Usage with protoc

    sh
    protoc -I. \
      --openapiv3_out=. \
      path/to/your/service.proto

    Hiding fields, methods, services and enum values

    If you require internal or unreleased fields and APIs to be hidden from
    your API documentation,
    google.api.VisibilityRule
    annotations can be added to services, methods, fields and enum values.
    The generator drops any annotated element whose restriction labels do
    not overlap with the configured visibility_restriction_selectors.
    Elements without a VisibilityRule annotation are always emitted.

    visibility_restriction_selectors can be declared multiple times to
    include multiple visibility restrictions in the output. For example,
    with buf:

    yaml
    version: v2
    plugins:
      - local: protoc-gen-openapiv3
        out: .
        opt:
          - visibility_restriction_selectors=PREVIEW
          - visibility_restriction_selectors=INTERNAL

    or with protoc:

    sh
    protoc --openapiv3_out=. \
      --openapiv3_opt=visibility_restriction_selectors=PREVIEW \
      --openapiv3_opt=visibility_restriction_selectors=INTERNAL \
      ./path/to/file.proto

    The restriction labels are arbitrary. INTERNAL and PREVIEW are the
    conventional pair, but any label scheme works (ALPHA, BETA,
    RELEASED, ...) as long as the annotations and the selector flag use
    the same vocabulary.

    When a service is hidden, all of its methods are hidden along with it
    and the service's tag is omitted from tags[]. When every field in a
    oneof group is hidden, the group's "at most one set" constraint is
    also dropped.

    Visibility annotations on fields used as HTTP path parameters (via
    google.api.http path templates) are ignored — the path template
    itself always exposes the parameter's name. To hide an operation that
    takes a restricted input, apply google.api.method_visibility to the
    method (or google.api.api_visibility to the whole service) instead
    of annotating the path field.

    If every value of an enum ends up hidden, the enum's component schema
    is still emitted (a visible field may reference it) but falls back to
    an unconstrained type: string. A log line is written when this
    happens; broaden the selectors or hide the referring fields to silence
    it.

    Mapping rules

    The mapping from proto constructs to OpenAPI is fixed and summarised below.

    Services and methods

    Proto OpenAPI
    Service Tag (tags[]) plus tags on each operation
    Method Operation under a PathItem
    Method leading comment Operation summary / description
    Method deprecated=true Operation deprecated: true
    Additional bindings Extra operations; operationId suffixed _

    The default operationId is <Service>_<Method>. When a method has multiple
    HTTP bindings, the first uses the bare ID and subsequent bindings append
    _1, _2, ... so the spec remains valid.

    The service's tag is named after the service and described by its leading
    comment. The service-level openapiv3_tag annotation overrides it: a
    non-empty name renames the tag, which the service's operations then use by
    default, and description, external_docs and extensions set the
    corresponding fields of the OpenAPI
    Tag Object. An
    operation-level openapiv3_operation.tags list still replaces the default for
    that operation.

    protobuf
    import "protoc-gen-openapiv3/options/annotations.proto";
    
    service BookService {
      option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_tag) = {
        name: "Books"
        description: "Manage the books in the library."
        external_docs: {
          description: "Library guide"
          url: "https://example.com/docs/books"
        }
      };
    
      rpc GetBook(GetBookRequest) returns (Book) {
        option (google.api.http) = {get: "/v1/books/{id}"};
      }
    }

    Parameters

    • Path parameters from the google.api.http URL template become in: path
      parameters.

    • Constrained path templates like {name=shelves/*} are expanded into
      the OpenAPI URL verbatim: the literal prefix stays in the URL and each
      wildcard becomes its own OpenAPI parameter. This is required because the
      proto field binds to the full matched substring (e.g. shelves/abc), so
      a client following the OpenAPI URL must actually send /shelves/abc
      rather than just /abc. Examples:

      Proto template OpenAPI URL
      /v1/{name} /v1/{name}
      /v1/{name=shelves/*} /v1/shelves/{name}
      /v1/{name=shelves/*/books/*} /v1/shelves/{name}/books/{name_1}
      /v1/{name=files/**} /v1/files/{name}

      When a single proto field expands into multiple wildcards, the second and
      subsequent parameters are suffixed _1, _2, ... so the OpenAPI URL
      stays valid. All synthetic parameters point back at the same underlying
      proto field, which the grpc-gateway runtime reconstructs from the full
      matched substring at request time.

    • Fields that are neither path parameters nor part of the request body
      become in: query parameters. This also applies to nested fields: with
      /v1/{id.value}, id.value is only a path parameter, while the other
      fields of id are still flattened into query parameters.

    • body="*" synthesises an inline object schema that includes every request
      field except path parameters.

    • body="field" uses that single field's type as the request body.

    Schemas

    • Messages become component schemas under #/components/schemas/.
    • Enums become string-valued component schemas.
    • repeated fields produce type: array.
    • Map fields produce type: object with additionalProperties.
    • 64-bit integer fields are emitted as JSON strings, matching protojson.
    • Well-known types are inlined, not referenced (see below).
    • Field descriptions are populated from leading proto comments.
    • google.api.field_behavior maps to required, readOnly, and
      writeOnly on the parent schema.
    • deprecated = true on a field sets deprecated: true on the property.

    Oneofs

    Every field inside a oneof appears as a normal property on the component
    schema, and each oneof group contributes an "at most one set" constraint
    on top of those properties. The constraint is expressed as a JSON Schema
    oneOf whose options are:

    1. a "none of the fields are set" guard of the form
      {"not": {"anyOf": [{"required": ["fieldA"]}, {"required": ["fieldB"]}, ...]}};
    2. one {"required": ["fieldN"]} option per field in the group.

    Because oneOf matches exactly one sub-schema:

    • zero fields set → only option 1 matches → passes,
    • exactly one field set → only that field's required option matches → passes,
    • two or more set → multiple required options match → fails validation.

    This matches proto3 oneof semantics, which allow either zero or one
    member to be set.

    Messages with a single oneof group hoist the constraint directly onto
    the component schema's oneOf. Messages with multiple groups wrap their
    group constraints in allOf so each group is enforced independently.

    Single-field oneof groups produce a trivially-true constraint and are
    skipped for output hygiene. Synthetic proto3-optional oneofs are treated
    as regular optional fields (the proto compiler models optional string foo = 1; as a one-element synthetic oneof).

    Well-known types

    Well-known types are inlined as their protojson representation:

    WKT Schema
    google.protobuf.Timestamp string, format: date-time
    google.protobuf.Duration string
    google.protobuf.FieldMask string
    google.protobuf.StringValue string
    google.protobuf.BytesValue string, format: byte
    google.protobuf.Int32Value integer, format: int32
    google.protobuf.UInt32Value integer, format: int64
    google.protobuf.Int64Value string, format: int64
    google.protobuf.UInt64Value string, format: uint64
    google.protobuf.FloatValue number, format: float
    google.protobuf.DoubleValue number, format: double
    google.protobuf.BoolValue boolean
    google.protobuf.Empty object
    google.protobuf.Struct object
    google.protobuf.Value unconstrained
    google.protobuf.ListValue array of unconstrained
    google.protobuf.NullValue null
    google.protobuf.Any object with @type plus open

    Wrapper types are intentionally not marked nullable. The strictly-correct
    JSON Schema 2020-12 form for google.protobuf.StringValue would be
    type: ["string", "null"], but no Go OpenAPI generator in the ecosystem
    handles that form today: openapi-generator-cli's Go target produces
    unbuildable code, and oapi-codegen (including its experimental 3.1 fork)
    errors with unhandled Schema type: &[string null] on request bodies.
    Until tooling catches up, the generator describes wrappers as their
    underlying primitive. The grpc-gateway runtime still accepts a JSON null
    on the wire regardless, because protojson treats wrappers as optional.

    RPCs returning google.protobuf.Empty emit a 200 with an object schema
    body ({}), matching what the grpc-gateway runtime actually writes on
    the wire. The HTTP-conventional 204 No Content would be more idiomatic
    but conflicts with runtime behaviour, so generated clients would reject
    valid responses.

    Error responses

    Every operation automatically gets a default response keyed to a
    component schema named google.rpc.Status with the standard code,
    message, and details[] fields. This matches what grpc-gateway returns
    on error paths. Use the disable_default_errors plugin option to suppress
    this behaviour when using a custom error handler.

    Security schemes

    Security schemes are declared once in the file-level openapiv3_document
    annotation, under components.security_schemes, and referenced by name from
    security requirements. A document-level security list applies to every
    operation in the file; an operation-level security list replaces it for that
    operation. Each entry in a security list is an alternative, and all schemes
    named within one entry must be satisfied together.

    The fields map to the OpenAPI
    Security Scheme Object
    and Security Requirement Object.
    Generation fails if a scheme is missing a field the spec requires for its type,
    or if a requirement names a scheme that isn't declared in the same file.

    protobuf
    import "protoc-gen-openapiv3/options/annotations.proto";
    
    option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_document) = {
      components: {
        security_schemes: {
          key: "BearerAuth"
          value: {
            type: TYPE_HTTP
            scheme: "bearer"
            bearer_format: "JWT"
          }
        }
        security_schemes: {
          key: "ApiKeyAuth"
          value: {
            type: TYPE_API_KEY
            name: "X-API-Key"
            in: IN_HEADER
          }
        }
        security_schemes: {
          key: "OAuth2"
          value: {
            type: TYPE_OAUTH2
            flows: {
              authorization_code: {
                authorization_url: "https://example.com/oauth/authorize"
                token_url: "https://example.com/oauth/token"
                scopes: {
                  key: "read"
                  value: "Read access"
                }
                scopes: {
                  key: "write"
                  value: "Write access"
                }
              }
            }
          }
        }
      }
      // Every operation requires a bearer token unless it says otherwise.
      security: {
        schemes: {
          key: "BearerAuth"
          value: {}
        }
      }
    };

    An operation can require different schemes, ask for OAuth2 scopes, or accept
    any of several alternatives:

    protobuf
    rpc UpdateBook(UpdateBookRequest) returns (Book) {
      option (google.api.http) = {
        patch: "/v1/books/{book.id}"
        body: "book"
      };
      // Either an OAuth2 token with the "write" scope, or an API key.
      option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_operation) = {
        security: {
          schemes: {
            key: "OAuth2"
            value: {scopes: "write"}
          }
        }
        security: {
          schemes: {
            key: "ApiKeyAuth"
            value: {}
          }
        }
      };
    }

    To make authentication optional for an operation, add an empty requirement.
    It renders as {} in the operation's security list:

    protobuf
    rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {
      option (google.api.http) = {get: "/v1/books"};
      option (grpc.gateway.protoc_gen_openapiv3.options.openapiv3_operation) = {
        security: {}
      };
    }

    Mutual TLS (TYPE_MUTUAL_TLS) needs no other fields, and OpenID Connect
    (TYPE_OPEN_ID_CONNECT) needs open_id_connect_url.

    Example

    Given:

    protobuf
    syntax = "proto3";
    
    package example.v1;
    
    import "google/api/annotations.proto";
    
    service EchoService {
      rpc Echo(EchoRequest) returns (EchoResponse) {
        option (google.api.http) = {
          post: "/v1/echo"
          body: "*"
        };
      }
    }
    
    message EchoRequest  { string message = 1; }
    message EchoResponse { string message = 1; }

    The generator emits echo.openapi.json with one POST /v1/echo operation,
    an EchoResponse component schema, and the auto-injected
    google.rpc.Status default error response. See
    protoc-gen-openapiv3/internal/genopenapi/testdata/simple_echo.openapi.json
    for the exact output.

    Consuming the output

    The generated spec validates as OpenAPI 3.1.0 and can be fed to any 3.1-aware
    tool, including openapi-generator-cli
    for client generation. An end-to-end example that runs a real grpc-gateway
    behind a generated Go client lives at
    examples/internal/integration/openapiv3.


    Docs Mapping Openapi V3 Merge (`docs/docs/mapping/openapi_v3_merge.md`)


    layout: default title: Merging OpenAPI 3.1 Output nav_order: 8 parent: Mapping

    Merging OpenAPI 3.1 Output

    {: .note }
    This page describes openapiv3-merge, the post-processing tool that
    combines protoc-gen-openapiv3 output into a single OpenAPI document. The
    generator itself is documented under
    OpenAPI 3.1 Output.

    protoc-gen-openapiv3 emits one OpenAPI document per
    proto file
    , matching the protobuf convention of 1:1 input-to-output
    files. Many OpenAPI consumers — UI viewers, client generators, gateway
    configurations — expect a single document instead. openapiv3-merge is the
    post-processing step that combines the per-file outputs into one.

    Installation

    sh
    go install github.com/grpc-ecosystem/grpc-gateway/v2/openapiv3-merge@latest

    Usage

    sh
    openapiv3-merge FILE [FILE ...] > merged.openapi.json

    The merged document is written to stdout. Errors go to stderr and the
    process exits with a non-zero status. Input order matters: the first
    input's info, servers, and externalDocs are kept in the merged
    document, so put the file with the broadest scope (the one carrying any
    shared openapiv3_document annotation) first.

    With buf

    Generate per-proto-file documents the usual way, then merge them:

    sh
    #!/usr/bin/env bash
    set -euo pipefail
    
    buf generate
    
    # Put the file with the shared openapiv3_document annotation first so
    # its info/servers/externalDocs are kept, then everything else in
    # sorted order for determinism.
    root=gen/api/v1/api.openapi.json
    mapfile -t rest < <(find gen -name '*.openapi.json' ! -path "$root" | sort)
    openapiv3-merge "$root" "${rest[@]}" > gen/api.openapi.json

    If you don't have a designated root file, just sort all inputs and accept
    whichever sorts first — but set the openapiv3_document annotation on
    that proto so the merged output has a sensible title, version, and
    servers.

    With protoc

    sh
    #!/usr/bin/env bash
    set -euo pipefail
    
    protoc -I. \
      --openapiv3_out=./gen \
      $(find . -name '*.proto')
    
    root=gen/api/v1/api.openapi.json
    mapfile -t rest < <(find gen -name '*.openapi.json' ! -path "$root" | sort)
    openapiv3-merge "$root" "${rest[@]}" > gen/api.openapi.json

    One-shot

    For trivial trees where any input may go first:

    sh
    openapiv3-merge $(find . -name '*.openapi.json' | sort) > api.openapi.json

    What gets merged, and how

    Field Rule
    openapi Must match across all inputs.
    info, servers, externalDocs Taken from the first input. Later inputs' values are dropped.
    paths, webhooks Unioned in input order. Path collisions with non-identical content are errors.
    components/* Unioned with sorted keys. Same name with non-identical content is an error.
    tags Deduplicated by name. Same name with non-identical metadata is an error.
    security First input to declare a non-empty array wins. Later inputs that declare a different non-empty array are an error.
    Unknown top-level keys (extensions, x-*) Taken from the first input.

    "Non-identical content" is determined by canonical comparison: two values
    that differ only in key order compare equal. Since protoc-gen-openapiv3
    names component schemas with their fully qualified proto name (e.g.
    example.v1.User), the same message reused across packages contributes a
    single, identical component to every output, and the merger combines them
    cleanly.

    The first input controls the merged document's info block. If you want a
    shared title, version, contact, license, or set of servers across all
    merged output, set them with an
    openapiv3_document annotation on the
    proto file that appears first in your merge invocation.

    Output

    • Top-level fields are emitted in OpenAPI 3.1.0 declaration order
      (openapi, info, servers, paths, webhooks, components,
      security, tags, externalDocs, then any extensions).
    • paths and webhooks are emitted in input order.
    • components/* sub-maps are sorted lexicographically, matching what
      protoc-gen-openapiv3 itself emits per file.
    • tags are emitted in first-occurrence order across inputs.

    Example merge errors

    When a merge fails, the error message identifies the conflicting field:

    text
    openapiv3-merge: paths."/v1/echo": echo.openapi.json redefines an entry with a different value

    Common causes:

    • Conflicting path definitions. Two protos declared the same HTTP path
      with different bindings. Decide which one is authoritative.
    • Conflicting component definitions. Two messages with the same fully
      qualified proto name but different shapes — usually means a duplicate
      package + message declaration somewhere in your proto tree.
    • Conflicting tag metadata. Two openapiv3_document.tags annotations
      described the same tag with different descriptions. Make them match or
      move the metadata to one place.
    • Mismatched OpenAPI versions. All inputs must declare the same
      openapi value.

    See also


    Docs Mapping Patch Feature (`docs/docs/mapping/patch_feature.md`)


    layout: default title: Patch feature nav_order: 2 parent: Mapping

    Patch feature

    The HTTP PATCH method allows a resource to be partially updated.

    If a binding is mapped to patch and the request message has exactly one FieldMask message in it, additional code is rendered for the gateway handler that will populate the FieldMask based on the request body. FieldMask is treated as a regular field by the gateway if the request method is not PATCH, or if the HttpRule body is "*"

    There are two scenarios:

    • The FieldMask is hidden from the REST request as per the
      Google API design guide (as in the first additional binding in the
      UpdateV2 example). In this case, the FieldMask is updated from the request body and set in the gRPC request message.
      • By default this feature is enabled, if you need to disable it, you can use the plugin option allow_patch_feature=false.
      • Note: The same option is supported by the protoc-gen-openapiv2 plugin.
    • The FieldMask is exposed to the REST request (as in the second additional binding in the UpdateV2 example). For this case, the field mask is left untouched by the gateway.

    Example Usage

    1. Create a PATCH request.

      The PATCH request needs to include the message and the update mask.

      protobuf
      // UpdateV2Request request for update includes the message and the update mask
      message UpdateV2Request {
       ABitOfEverything abe = 1;
       google.protobuf.FieldMask update_mask = 2;
      }
    2. Define your service in gRPC

      If you want to use PATCH with fieldmask hidden from REST request only include the request message in the body.

      protobuf
      rpc UpdateV2(UpdateV2Request) returns (google.protobuf.Empty) {
       option (google.api.http) = {
         put: "/v2/example/a_bit_of_everything/{abe.uuid}"
         body: "abe"
         additional_bindings {
           patch: "/v2/example/a_bit_of_everything/{abe.uuid}"
           body: "abe"
         }
       };
      }

      If you want to use PATCH with fieldmask exposed to the REST request then include the entire request message.

      protobuf
      rpc UpdateV2(UpdateV2Request) returns (google.protobuf.Empty) {
       option (google.api.http) = {
         patch: "/v2a/example/a_bit_of_everything/{abe.uuid}"
         body: "*"
       };
      }
    3. Generate gRPC and reverse-proxy stubs and implement your service.

    cURL examples

    In the example below, we will partially update our ABitOfEverything resource by passing only the field we want to change. Since we are using the endpoint with field mask hidden we only need to pass the field we want to change ("string_value") and it will keep everything else in our resource the same.

    sh
    $ curl \
      --data '{"stringValue": "strprefix/foo"}' \
      -X PATCH \
      http://address:port/v2/example/a_bit_of_everything/1

    If we know what fields we want to update then we can use PATCH with field mask approach. For this, we need to pass the resource and the update_mask. Below only the "single_nested" will get updated because that is what we specify in the field_mask.

    sh
    $ curl \
      --data '{"abe":{"singleNested":{"amount":457},"stringValue":"some value that will not get updated because not in the field mask"},"updateMask":"singleNested"}}' \
      -X PATCH \
      http://address:port/v2a/example/a_bit_of_everything/1

    Docs Mapping Using Ref With Responses (`docs/docs/mapping/using_ref_with_responses.md`)

    Using arbitrary messages in response description

    Assuming a protobuf file of the structure

    protobuf
    syntax = "proto3";
    
    package example.service.v1;
    
    import "protoc-gen-openapiv2/options/annotations.proto";
    
    service GenericService {
      rpc GenericRPC(GenericRPCRequest) returns (GenericRPCResponse);
    }
    
    message GenericRPCRequest {
      string id = 1;
    }
    
    message GenericRPCResponse {
      string result = 1;
    }

    If you want your OpenAPI document to include a custom response for all RPCs defined in this protobuf file, you can add the following:

    protobuf
    option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
      responses: {
        key: "400"
        value: {
          description: "Returned when the request is malformed."
          schema: {
            json_schema: {ref: ".example.service.v1.GenericResponse"} // Must match the fully qualified name of the message
          }
        }
      }
    };
    
    message GenericResponse {
      repeated string resources = 1;
      repeated string errors = 2;
    }

    When generating, you will see the following response included in your OpenAPI document:

    json
    "400": {
      "description": "Returned when the request is malformed.",
      "schema": {
        "$ref": "#/definitions/v1GenericResponse"
      }
    },

    The annotation can also be specified per-rpc.


    Docs Operations Annotated Context (`docs/docs/operations/annotated_context.md`)


    layout: default title: Extracting the HTTP path pattern for a request nav_order: 4 parent: Operations

    Extracting the HTTP path pattern for a request

    It is often interesting to know what HTTP path pattern was matched for a specific request, for example for metrics. This article explains how to extract the HTTP path pattern from the request context.

    Get HTTP Path pattern

    1. Define the HTTP path in the proto annotation. For example:
    proto
    syntax = "proto3";
    option go_package = "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/proto/examplepb";
    package grpc.gateway.examples.internal.proto.examplepb;
    
    import "google/api/annotations.proto";
    
    service LoginService {
      rpc Login (LoginRequest) returns (LoginReply) {
        option (google.api.http) = {
            post: "/v1/example/login"
            body: "*"
        };
      }
    }
    
    message LoginRequest {}
    
    message LoginReply {}
    1. At runtime, get the HTTP path pattern from the annotated context, for example using the WithMetadata function.
      You can pass data to your backend by adding them to the gRPC metadata or push them to a metrics server.
    go
    mux := runtime.NewServeMux(
    	runtime.WithMetadata(func(ctx context.Context, r *http.Request) metadata.MD {
    		md := make(map[string]string)
    		if method, ok := runtime.RPCMethod(ctx); ok {
    			md["method"] = method // /grpc.gateway.examples.internal.proto.examplepb.LoginService/Login
    		}
    		if pattern, ok := runtime.HTTPPathPattern(ctx); ok {
    			md["pattern"] = pattern // /v1/example/login
    		}
    		return metadata.New(md)
    	}),
    )

    Docs Operations Aws Gateway Integration (`docs/docs/operations/aws_gateway_integration.md`)


    layout: default title: AWS gateway integration nav_order: 3 parent: Operations

    AWS gateway integration

    Import OpenAPI documentation into AWS API Gateway

    The AWS API Gateway service allows importing of an OpenAPI specification to create a REST API. The process is very straightforward and can be found here.

    Here are some tips to consider when importing the documentation:

    1. Remove any circular dependencies (these aren't supported by the parser).
    2. Remove security-related annotations (These annotations aren't well supported by the parser).
    3. Max length of fields are reviewed by the parser but the errors aren't self-explanatory. Review the specification to verify that the requirements are met.
    4. API gateway errors aren't great, but you can use this page for structure validation.

    Docs Operations Health Check (`docs/docs/operations/health_check.md`)


    layout: default title: Health check nav_order: 1 parent: Operations

    Health check

    With the [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md)

    To use the gRPC health checking protocol you must add the two health checking methods, Watch and Check.

    Registering the health server

    1. Add google.golang.org/grpc/health/grpc_health_v1 to your imports
    2. Register the health server with grpc_health_v1.RegisterHealthServer(grpcServer, yourService)

    Adding the health check methods

    1. Check method
    go
    func (s *serviceServer) Check(ctx context.Context, in *health.HealthCheckRequest) (*health.HealthCheckResponse, error) {
    	return &health.HealthCheckResponse{Status: health.HealthCheckResponse_SERVING}, nil
    }
    1. Watch method
    go
    func (s *serviceServer) Watch(in *health.HealthCheckRequest, _ health.Health_WatchServer) error {
        // Example of how to register both methods but only implement the Check method.
    	return status.Error(codes.Unimplemented, "unimplemented")
    }
    1. You can test the functionality with GRPC health probe.

    Adding `/healthz` endpoint to runtime.ServeMux

    To automatically register a /healthz endpoint in your ServeMux you can use
    the ServeMuxOption WithHealthzEndpoint
    which takes in a connection to your registered gRPC server.

    This endpoint will forward a request to the Check method described above to really check the health of the
    whole system, not only the gateway itself. If your server doesn't implement the health checking protocol each request
    to /healthz will result in the following:

    json
    {"code":12,"message":"unknown service grpc.health.v1.Health","details":[]}

    If you've implemented multiple services in your server you can target specific services with the ?service=<service>
    query parameter. This will then be added to the health.HealthCheckRequest in the Service property. With that you can
    write your own logic to handle that in the health checking methods.

    Analogously, to register an {/endpoint/path} endpoint in your ServeMux with a user-defined endpoint path, you can use
    the ServeMuxOption WithHealthEndpointAt, which accepts a connection to your registered gRPC server
    together with a custom endpointPath string parameter.


    Docs Operations Inject Router (`docs/docs/operations/inject_router.md`)


    layout: default title: Adding custom routes to the mux nav_order: 0 parent: Operations

    Adding custom routes to the mux

    The gRPC-Gateway allows you to add custom routes to the serve mux, for example, if you want to support a use case that isn't supported by the gRPC-Gateway, like file uploads.

    Example

    go
    package main
    
    import (
    	"context"
    	"net/http"
    
    	pb "github.com/grpc-ecosystem/grpc-gateway/v2/examples/internal/helloworld"
    	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    )
    
    func main() {
    	ctx := context.TODO()
    	mux := runtime.NewServeMux()
    	// Register generated routes to mux
    	err := pb.RegisterGreeterHandlerServer(ctx, mux, &GreeterServer{})
    	if err != nil {
    		panic(err)
    	}
    	// Register custom route for  GET /hello/{name}
    	err = mux.HandlePath("GET", "/hello/{name}", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
    		w.Write([]byte("hello " + pathParams["name"]))
    	})
    	if err != nil {
    		panic(err)
    	}
    	http.ListenAndServe(":8080", mux)
    }
    
    // GreeterServer is the server API for Greeter service.
    type GreeterServer struct {
    
    }
    
    // SayHello implement to say hello
    func (h *GreeterServer) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
    	return &pb.HelloReply{
    		Message: "hello " + req.Name,
    	}, nil
    }

    Docs Operations Logging (`docs/docs/operations/logging.md`)


    layout: default title: Logging the request body pattern for a request nav_order: 5 parent: Operations

    Logging the request body pattern for a request

    If you want to log the request body of incoming requests, you will need to buffer the body before it reaches the gateway. To log the request body, you can use a middleware http.Handler to buffer the request body before it's consumed.

    1. Create a http.Handler middleware. The logRequestBody example middleware logs the request body when the response status code is not 200.
    go
    type logResponseWriter struct {
    	http.ResponseWriter
    	statusCode int
    }
    
    func (rsp *logResponseWriter) WriteHeader(code int) {
    	rsp.statusCode = code
    	rsp.ResponseWriter.WriteHeader(code)
    }
    
    // Unwrap returns the original http.ResponseWriter. This is necessary
    // to expose Flush() and Push() on the underlying response writer.
    func (rsp *logResponseWriter) Unwrap() http.ResponseWriter {
    	return rsp.ResponseWriter
    }
    
    func newLogResponseWriter(w http.ResponseWriter) *logResponseWriter {
    	return &logResponseWriter{w, http.StatusOK}
    }
    
    // logRequestBody logs the request body when the response status code is not 200.
    func logRequestBody(h http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		lw := newLogResponseWriter(w)
    
    		// Note that buffering the entire request body could consume a lot of memory.
    		body, err := io.ReadAll(r.Body)
    		if err != nil {
    			http.Error(w, fmt.Sprintf("failed to read body: %v", err), http.StatusBadRequest)
    			return
    		}
    		clonedR := r.Clone(r.Context())
    		clonedR.Body = io.NopCloser(bytes.NewReader(body))
    
    		h.ServeHTTP(lw, clonedR)
    
    		if lw.statusCode != http.StatusOK {
    			grpclog.Errorf("http error %+v request body %+v", lw.statusCode, string(body))
    		}
    	})
    }
    1. Wrap the gateway serve mux with the logRequestBody middleware:
    go
    mux := runtime.NewServeMux()
        // Register generated gateway handlers
    
        s := &http.Server{
            Handler: logRequestBody(mux),
        }

    Docs Operations Security Considerations (`docs/docs/operations/security_considerations.md`)


    layout: default title: Security considerations nav_order: 6 parent: Operations

    Security considerations

    Things worth knowing about the defaults before you put a gateway in front of a
    service that matters.

    Unknown JSON fields are dropped, and nothing says so

    By default the gateway unmarshals JSON with protojson configured as
    DiscardUnknown: true. A field that the target message does not define is
    removed during transcoding and the request continues as if it had never been
    sent.

    Given this service:

    proto
    message Command {
      string action = 1;
      int32  amount = 2;
    }
    
    service Gateway {
      rpc Send(Command) returns (Ack) {
        option (google.api.http) = {
          post: "/v1/send"
          body: "*"
        };
      }
    }

    a request carrying a third field:

    text
    POST /v1/send  {"action":"transfer","amount":1,"auth":"..."}

    reaches the backend as action and amount only. The auth field is gone,
    the backend sees a well formed message, and the client gets 200 OK. Neither
    end is told that anything was removed.

    This is the behaviour the proto3 JSON mapping describes, and other JSON to gRPC
    transcoders default the same way, so a client that works against one of them
    will behave the same here. It is worth stating plainly because it is more
    lenient than the protojson library the gateway wraps, which rejects unknown
    fields by default.

    When this matters

    The case to watch for is a client that puts something in the request expecting
    the server to act on it, where the field is not in the schema. A token added by
    an intermediary, a tenant identifier, a signature over the body, a flag a newer
    client sends to an older backend. All of these disappear quietly, and the
    request still succeeds, so the failure does not look like a failure.

    It also matters when the schema changes. Removing or renaming a field does not
    break clients that still send it. That is often the point, but it means a
    rename can silently stop delivering data that the backend used to receive.

    Rejecting unknown fields instead

    Set DiscardUnknown to false on the marshaler:

    go
    mux := runtime.NewServeMux(
    	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
    		MarshalOptions: protojson.MarshalOptions{
    			UseProtoNames: true,
    		},
    		UnmarshalOptions: protojson.UnmarshalOptions{
    			DiscardUnknown: false,
    		},
    	}),
    )

    The same request now returns 400 with unknown field "auth".

    This is a good default for an internal API where every client is yours and a
    stray field means someone made a mistake. It is a poor default for a public API
    where clients you do not control may send extra fields for reasons of their
    own, since it turns forward compatibility into an error.

    Noticing without rejecting

    If rejecting is too strict but silence is too quiet, you can unmarshal twice and
    log the difference: once with DiscardUnknown: false to see whether the strict
    parse would have failed, then with the permissive setting for the request that
    actually proceeds. That costs an extra parse per request, so it suits a
    canary or a sampled fraction of traffic rather than everything.

    See also


    Docs Operations Tracing (`docs/docs/operations/tracing.md`)


    layout: default title: Tracing nav_order: 2 parent: Operations

    Tracing

    If you are starting a new project, jump to the OpenTelemetry
    section below. OpenTelemetry is the current standard for tracing in the Go
    ecosystem and, when combined with otelhttp and otelgrpc, propagates spans
    through the gateway with no custom middleware. The
    OpenCensus and
    OpenTracing sections below are kept for existing
    integrations and are considered legacy.

    With [OpenCensus.io](https://opencensus.io/) and [AWS X-ray](https://aws.amazon.com/xray/)

    Legacy: OpenCensus is deprecated in favor of OpenTelemetry. See the
    OpenTelemetry section for the current approach.

    Adding tracing using AWS-Xray as the exporter

    This example uses the AWS-Xray exporter with a global trace setting. Note that AWS X-ray exporter does not handle any metrics only tracing.

    1. Add the following imports
    go
    xray "contrib.go.opencensus.io/exporter/aws"
    "go.opencensus.io/plugin/ocgrpc"
    "go.opencensus.io/plugin/ochttp"
    "go.opencensus.io/trace"
    1. Register the AWS X-ray exporter for the GRPC server
    go
    xrayExporter, err := xray.NewExporter(
        xray.WithVersion("latest"),
        // Add your AWS region.
        xray.WithRegion("ap-southeast-1"),
    )
    if err != nil {
        // Handle any error.
    }
    // Do not forget to call Flush() before the application terminates.
    defer xrayExporter.Flush()
    
    // Register the trace exporter.
    trace.RegisterExporter(xrayExporter)
    1. Add a global tracing configuration
    go
    // Always trace in this example.
    // In production this can be set to a trace.ProbabilitySampler.
    trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
    1. Add ocgrpc.ClientHandler for tracing the gRPC client calls
    go
    conn, err := grpc.NewClient(
        // Other options goes here.
        // Add ocgrpc.ClientHandler for tracing the grpc client calls.
        grpc.WithStatsHandler(&ocgrpc.ClientHandler{}),
    )
    1. Wrap the gateway mux with the OpenCensus HTTP handler
    go
    gwmux := runtime.NewServeMux()
    
    openCensusHandler := &ochttp.Handler{
    		Handler: gwmux,
    }
    
    gwServer := &http.Server{
        Addr: "0.0.0.0:10000",
        Handler: openCensusHandler,
        }),
    }

    Without a global configuration

    In this example we have added the gRPC Health Checking Protocol and we do not wish to trace any health checks.

    1. Follow step 1, 2 and 4 from the previous section.

    2. Since we are not using a global configuration we can decide what paths we want to trace.

    go
    gwmux := runtime.NewServeMux()
    
    openCensusHandler := &ochttp.Handler{
        Handler: gwmux,
        GetStartOptions: func(r *http.Request) trace.StartOptions {
            startOptions := trace.StartOptions{}
            if strings.HasPrefix(r.URL.Path, "/api") {
                // This example will always trace anything starting with /api.
                startOptions.Sampler = trace.AlwaysSample()
            }
            return startOptions
        },
    }
    1. No global configuration means we have to use the per span sampler.

    A method we want to trace

    go
    func (s *service) Name(ctx context.Context, req *pb.Request) (*pb.Response, error) {
        // Here we add the span ourselves.
        ctx, span := trace.StartSpan(ctx, "name.to.use.in.trace", trace.
        // Select a sampler that fits your implementation.
        WithSampler(trace.AlwaysSample()))
        defer span.End()
        /// Other stuff goes here.
    }

    A method we do not wish to trace

    go
    func (s *service) Check(ctx context.Context, in *health.HealthCheckRequest) (*health.HealthCheckResponse, error) {
        // Note no span here.
        return &health.HealthCheckResponse{Status: health.HealthCheckResponse_SERVING}, nil
    }

    OpenTracing Support (legacy)

    Legacy: OpenTracing is deprecated in favor of OpenTelemetry. The custom
    tracingWrapper middleware below is only needed for OpenTracing. With
    OpenTelemetry's otelhttp and otelgrpc no such wrapper is required — see the
    OpenTelemetry section.

    If your project uses OpenTracing and you'd like spans to propagate through the gateway, you can add some middleware which parses the incoming HTTP headers to create a new span correctly.

    go
    import (
    	"github.com/opentracing/opentracing-go"
    	"github.com/opentracing/opentracing-go/ext"
    )
    
    var grpcGatewayTag = opentracing.Tag{Key: string(ext.Component), Value: "grpc-gateway"}
    
    func tracingWrapper(h http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		parentSpanContext, err := opentracing.GlobalTracer().Extract(
    			opentracing.HTTPHeaders,
    			opentracing.HTTPHeadersCarrier(r.Header))
    		if err == nil || err == opentracing.ErrSpanContextNotFound {
    			serverSpan := opentracing.GlobalTracer().StartSpan(
    				"ServeHTTP",
    				// this is magical, it attaches the new span to the parent parentSpanContext, and creates an unparented one if empty.
    				ext.RPCServerOption(parentSpanContext),
    				grpcGatewayTag,
    			)
    			r = r.WithContext(opentracing.ContextWithSpan(r.Context(), serverSpan))
    			defer serverSpan.Finish()
    		}
    		h.ServeHTTP(w, r)
    	})
    }
    
    // Then just wrap the mux returned by runtime.NewServeMux() like this
    if err := http.ListenAndServe(":8080", tracingWrapper(mux)); err != nil {
    	log.Fatalf("failed to start gateway server on 8080: %v", err)
    }

    Finally, don't forget to add a tracing interceptor when registering
    the services. E.g.

    go
    import (
    	"google.golang.org/grpc"
    	"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
    )
    
    opts := []grpc.DialOption{
    	grpc.WithUnaryInterceptor(
    		grpc_opentracing.UnaryClientInterceptor(
    			grpc_opentracing.WithTracer(opentracing.GlobalTracer()),
    		),
    	),
    }
    if err := pb.RegisterMyServiceHandlerFromEndpoint(ctx, mux, serviceEndpoint, opts); err != nil {
    	log.Fatalf("could not register HTTP service: %v", err)
    }

    OpenTelemetry

    OpenTelemetry is the recommended way to trace
    requests through the gateway. You do not need a custom tracingWrapper (as in
    the legacy OpenTracing section above).
    The official instrumentation libraries
    already do the work:

    • otelhttp
      wraps the gateway http.Handler, extracts the incoming
      W3C Trace Context from the request
      headers, and starts the HTTP server span.
    • otelgrpc
      stats handlers start the gRPC client span for the gateway's outgoing call
      (injecting the trace context into the gRPC metadata) and the gRPC server
      span
      on the backend.

    An incoming HTTP request therefore produces three connected parent/child spans
    that share a single trace ID:

    text
    HTTP server span (otelhttp)  ->  gRPC client span (otelgrpc)  ->  gRPC server span (otelgrpc)

    Runnable example

    A complete, self-contained example lives at
    examples/internal/cmd/example-otel-tracing.
    In a single process it wires up a stdout span exporter, an instrumented
    in-process gRPC backend, and the gateway. Run it with:

    shell
    go run ./examples/internal/cmd/example-otel-tracing
    # then, in another terminal:
    curl http://localhost:8081/say/OpenTelemetry

    Wiring

    Install a TracerProvider and a propagator once at startup:

    go
    import (
    	"go.opentelemetry.io/otel"
    	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
    	"go.opentelemetry.io/otel/propagation"
    	sdktrace "go.opentelemetry.io/otel/sdk/trace"
    )
    
    exporter, err := stdouttrace.New(stdouttrace.WithPrettyPrint())
    if err != nil {
    	// Handle any error.
    }
    tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
    defer tp.Shutdown(context.Background())
    
    otel.SetTracerProvider(tp)
    otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
    	propagation.TraceContext{},
    	propagation.Baggage{},
    ))

    Instrument the gRPC backend with the server stats handler:

    go
    import "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
    
    s := grpc.NewServer(grpc.StatsHandler(otelgrpc.NewServerHandler()))

    Dial the backend with the client stats handler so the gateway's outgoing call is
    traced and the trace context is propagated:

    go
    conn, err := grpc.NewClient(
    	"localhost:9091",
    	grpc.WithTransportCredentials(insecure.NewCredentials()),
    	grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
    )

    Finally, wrap the gateway mux with otelhttp — this replaces the custom
    tracingWrapper entirely:

    go
    import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
    
    mux := runtime.NewServeMux()
    if err := pb.RegisterGreeterHandler(ctx, mux, conn); err != nil {
    	// Handle any error.
    }
    
    handler := otelhttp.NewHandler(mux, "grpc-gateway")
    if err := http.ListenAndServe(":8081", handler); err != nil {
    	log.Fatalf("failed to start gateway server: %v", err)
    }

    Sample output

    Issuing curl http://localhost:8081/say/OpenTelemetry prints three spans that
    all share the same TraceID, confirming the trace propagates through the
    gateway. Trimmed for brevity:

    jsonc
    // 1. HTTP server span (otelhttp) — the root span.
    {
    	"Name": "GET",
    	"SpanContext": { "TraceID": "6952...4aa5", "SpanID": "3b9c...fd0e" },
    	"Parent":      { "TraceID": "0000...0000", "SpanID": "0000...0000" },
    	"SpanKind": 2, // server
    	"InstrumentationScope": { "Name": ".../net/http/otelhttp" }
    }
    // 2. gRPC client span (otelgrpc) — child of the HTTP span.
    {
    	"Name": "grpc.gateway.examples.internal.helloworld.Greeter/SayHello",
    	"SpanContext": { "TraceID": "6952...4aa5", "SpanID": "1224...75ca" },
    	"Parent":      { "TraceID": "6952...4aa5", "SpanID": "3b9c...fd0e" },
    	"SpanKind": 3, // client
    	"InstrumentationScope": { "Name": ".../grpc/otelgrpc" }
    }
    // 3. gRPC server span (otelgrpc) — child of the client span, context received over the wire.
    {
    	"Name": "grpc.gateway.examples.internal.helloworld.Greeter/SayHello",
    	"SpanContext": { "TraceID": "6952...4aa5", "SpanID": "950f...d85e" },
    	"Parent":      { "TraceID": "6952...4aa5", "SpanID": "1224...75ca", "Remote": true },
    	"SpanKind": 2, // server
    	"InstrumentationScope": { "Name": ".../grpc/otelgrpc" }
    }

    Docs Overview Background (`docs/docs/overview/background.md`)


    layout: default title: Background nav_order: 0 parent: Overview

    Background

    gRPC is great -- it generates API clients and server stubs in many programming languages, it is fast, easy-to-use, bandwidth-efficient and its design is combat-proven by Google. However, you might still want to provide a traditional RESTful API as well. Reasons can range from maintaining backwards-compatibility, supporting languages or clients not well supported by gRPC to simply maintaining the aesthetics and tooling involved with a RESTful architecture.

    This project aims to provide that HTTP+JSON interface to your gRPC service. A small amount of configuration in your service to attach HTTP semantics is all that's needed to generate a reverse-proxy with this library.


    Docs Overview Usage (`docs/docs/overview/usage.md`)


    layout: default title: How do I use this? nav_order: 1 parent: Overview

    How do I use this?

    Follow the instructions in the README.


    Docs Tutorials Adding Annotations (`docs/docs/tutorials/adding_annotations.md`)


    layout: default title: Adding gRPC-Gateway annotations to an existing proto file nav_order: 4 parent: Tutorials

    Adding gRPC-Gateway annotations to an existing proto file

    Now that we've got a working Go gRPC server, we need to add the gRPC-Gateway annotations.

    The annotations define how gRPC services map to the JSON request and response. When using protocol buffers, each RPC must define the HTTP method and path using the google.api.http annotation.

    So we will need to add the google/api/http.proto import to the proto file. We also need to add the HTTP->gRPC mapping we want. In this case, we're mapping POST /v1/example/echo to our SayHello RPC.

    protobuf
    syntax = "proto3";
    
    package helloworld;
    
    import "google/api/annotations.proto";
    
    // Here is the overall greeting service definition where we define all our endpoints
    service Greeter {
      // Sends a greeting
      rpc SayHello (HelloRequest) returns (HelloReply) {
        option (google.api.http) = {
          post: "/v1/example/echo"
          body: "*"
        };
      }
    }
    
    // The request message containing the user's name
    message HelloRequest {
      string name = 1;
    }
    
    // The response message containing the greetings
    message HelloReply {
      string message = 1;
    }

    See a_bit_of_everything.proto for examples of more annotations you can add to customize gateway behavior.

    Generating the gRPC-Gateway stubs

    Now that we've got the gRPC-Gateway annotations added to the proto file, we need to use the gRPC-Gateway generator to generate the stubs.

    Using buf

    We'll need to add the gRPC-Gateway generator to the generation configuration:

    yaml
    version: v1
    plugins:
      - plugin: go
        out: proto
        opt: paths=source_relative
      - plugin: go-grpc
        out: proto
        opt: paths=source_relative,require_unimplemented_servers=false
      - plugin: grpc-gateway
        out: proto
        opt: paths=source_relative

    We'll also need to add the googleapis dependency to our buf.yaml file:

    yaml
    version: v1
    name: buf.build/myuser/myrepo
    deps:
      - buf.build/googleapis/googleapis

    Then we need to run buf mod update to select a version of the dependency to use.

    And that's it! Now if you run:

    sh
    $ buf generate

    It should produce a *.gw.pb.go file.

    Using `protoc`

    Before we can generate the stubs with protoc, we need to copy some dependencies into our proto file structure. Copy a subset of the googleapis
    from the official repository to your local proto file structure. It should look like this afterwards:

    text
    proto
    ├── google
    │   └── api
    │       ├── annotations.proto
    │       └── http.proto
    └── helloworld
        └── hello_world.proto

    Now we need to add the gRPC-Gateway generator to the protoc invocation:

    sh
    $ protoc -I ./proto \
      --go_out ./proto --go_opt paths=source_relative \
      --go-grpc_out ./proto --go-grpc_opt paths=source_relative \
      --grpc-gateway_out ./proto --grpc-gateway_opt paths=source_relative \
      ./proto/helloworld/hello_world.proto

    This should generate a *.gw.pb.go file.

    We also need to add and serve the gRPC-Gateway mux in our main.go file.

    text
    /* Detailed source-code truncated for AI context efficiency. */

    For more examples, please refer to our boilerplate repository.

    Testing the gRPC-Gateway

    Now we can start the server:

    sh
    $ go run main.go

    Then we use cURL to send HTTP requests:

    sh
    $ curl -X POST -k http://localhost:8090/v1/example/echo -d '{"name": " hello"}'
    text
    {"message":"hello world"}

    Hopefully, that gives a bit of understanding of how to use the gRPC-Gateway.

    Full source code of hello world program can be found here helloworld-grpc-gateway.

    Next{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }


    Docs Tutorials Creating Main.Go (`docs/docs/tutorials/creating_main.go.md`)


    layout: default title: Creating main.go nav_order: 3 parent: Tutorials

    Creating main.go

    Before creating main.go file we are assuming that the user has created a go.mod with the name github.com/myuser/myrepo, if not please refer to Creating go.mod file. The import here is using the path to the generated files in proto/helloworld relative to the root of the repository.

    go
    package main
    
    import (
    	"context"
    	"log"
    	"net"
    
    	"google.golang.org/grpc"
    
    	helloworldpb "github.com/myuser/myrepo/proto/helloworld"
    )
    
    type server struct{
    	helloworldpb.UnimplementedGreeterServer
    }
    
    func NewServer() *server {
    	return &server{}
    }
    
    func (s *server) SayHello(ctx context.Context, in *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
    	return &helloworldpb.HelloReply{Message: in.Name + " world"}, nil
    }
    
    func main() {
    	// Create a listener on TCP port
    	lis, err := net.Listen("tcp", ":8080")
    	if err != nil {
    		log.Fatalln("Failed to listen:", err)
    	}
    
    	// Create a gRPC server object
    	s := grpc.NewServer()
    	// Attach the Greeter service to the server
    	helloworldpb.RegisterGreeterServer(s, &server{})
    	// Serve gRPC Server
    	log.Println("Serving gRPC on 0.0.0.0:8080")
    	log.Fatal(s.Serve(lis))
    }

    Read More

    For more refer to gRPC docs https://grpc.io/docs/languages/go/.

    Next{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }


    Docs Tutorials Introduction (`docs/docs/tutorials/introduction.md`)


    layout: default title: Introduction to the gRPC-Gateway nav_order: 0 parent: Tutorials

    Introduction to the gRPC-Gateway

    We all know that gRPC is not a tool for everything. There are cases where we still want to provide a traditional HTTP/JSON API. The reasons can range from maintaining backward-compatibility to supporting programming languages or clients not well supported by gRPC. But writing another service just to expose an HTTP/JSON API is quite a time consuming and tedious task.

    So is there any way to code just once, but provide APIs in both gRPC and HTTP/JSON at the same time?

    The answer is Yes.

    The gRPC-Gateway is a plugin of the Google protocol buffers compiler protoc. It reads protobuf service definitions and generates a reverse-proxy server which translates a RESTful HTTP API into gRPC. This server is generated according to the google.api.http annotations in your service definitions.

    This helps you provide your APIs in both gRPC and HTTP/JSON format at the same time.

    Prerequisites

    Before we start coding, we have to install some tools.

    We will be using a Go gRPC server in the examples, so please install Go first from https://golang.org/dl/.

    After installing Go, use go install to download and build the following binaries:

    sh
    $ go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest
    $ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

    This installs the protoc generator plugins we need to generate the stubs. Make sure to add $GOPATH/bin to your $PATH so that executables installed via go get are available on your $PATH.

    We will be working in a new module for this tutorial, so go ahead and create that in a folder of your choosing now:

    Creating go.mod file

    Start your module using the go mod init command to create a go.mod file.

    Run the go mod init command, giving it the path of the module your code will be in. Here, use github.com/myuser/myrepo for the module path -- in production code, this would be the URL from which your module can be downloaded.

    sh
    $ go mod init github.com/myuser/myrepo
    go: creating new go.mod: module github.com/myuser/myrepo

    The go mod init command creates a go.mod file that identifies your code as a module that might be used from other code. The file you just created includes only the name of your module and the Go version your code supports. But as you add dependencies -- meaning packages from other modules -- the go.mod file will list the specific module versions to use. This keeps builds reproducible and gives you direct control over which module versions to use.

    Next{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }


    Docs Tutorials Learn More (`docs/docs/tutorials/learn_more.md`)


    layout: default title: Learn More nav_order: 5 parent: Tutorials

    Learn More

    How it works

    When the HTTP request arrives at the gRPC-Gateway, it parses the JSON data into a protobuf message. It then makes a normal Go gRPC client request using the parsed protobuf message. The Go gRPC client encodes the protobuf structure into the protobuf binary format and sends it to the gRPC server. The gRPC Server handles the request and returns the response in the protobuf binary format. The Go gRPC client parses it into a protobuf message and returns it to the gRPC-Gateway, which encodes the protobuf message to JSON and returns it to the original client.

    google.api.http

    Read more about google.api.http in the source file documentation.

    HTTP and gRPC Transcoding

    Read more about HTTP and gRPC Transcoding on AIP 127.


    Docs Tutorials Simple Hello World (`docs/docs/tutorials/simple_hello_world.md`)


    layout: default title: Creating a simple hello world with gRPC nav_order: 1 parent: Tutorials

    Creating a simple hello world with gRPC

    To understand the gRPC-Gateway we are going to first make a hello world gRPC service.

    Defining your gRPC service using protocol buffers

    Before we create a gRPC service, we should create a proto file to define what we need, here we create a file named hello_world.proto in the directory proto/helloworld/hello_world.proto.

    The gRPC service is defined using Google Protocol Buffers. To learn more about how to define a service in a .proto file see their Basics tutorial. For now, all you need to know is that both the server and the client stub have a SayHello() RPC method that takes a HelloRequest parameter from the client and returns a HelloReply from the server, and that the method is defined like this:

    protobuf
    syntax = "proto3";
    
    package helloworld;
    
    // The greeting service definition
    service Greeter {
      // Sends a greeting
      rpc SayHello (HelloRequest) returns (HelloReply) {}
    }
    
    // The request message containing the user's name
    message HelloRequest {
      string name = 1;
    }
    
    // The response message containing the greetings
    message HelloReply {
      string message = 1;
    }

    Next{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }


    Docs Tutorials Generating Stubs Using Buf (`docs/docs/tutorials/generating_stubs/using_buf.md`)


    layout: default title: Generating stubs using buf nav_order: 0 parent: Generating stubs grand_parent: Tutorials

    Generating stubs using buf

    Buf is a tool that provides various protobuf utilities such as linting, breaking change detection and generation. Please find installation instructions on https://docs.buf.build/installation/.

    It is configured through a buf.yaml file that should be checked in to the root of your Protobuf file hierarchy. Buf will automatically read this file if present. Configuration can also be provided via the command-line flag --config, which accepts a path to a .json or .yaml file, or direct JSON or YAML data. As opposed to protoc, where all .proto files are manually specified on the command-line, buf operates by recursively discovering all .proto files under configuration and building them.

    The following is an example of a valid configuration, and you would put it in the root of your Protobuf file hierarchy, e.g. in proto/buf.yaml relative to the root of your repository.

    yaml
    version: v1
    name: buf.build/myuser/myrepo

    To generate type and gRPC stubs for Go, create the file buf.gen.yaml:

    yaml
    version: v1
    plugins:
      - plugin: go
        out: proto
        opt: paths=source_relative
      - plugin: go-grpc
        out: proto
        opt: paths=source_relative

    We use the go and go-grpc plugins to generate Go types and gRPC service definitions. We're outputting the generated files relative to the proto folder, and we're using the paths=source_relative option, which means that the generated files will appear in the same directory as the source .proto file.

    Then run

    sh
    $ buf generate

    This will have generated a *.pb.go and a *_grpc.pb.go file for each protobuf package in our proto file hierarchy.

    Next{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }


    Docs Tutorials Generating Stubs Using Protoc (`docs/docs/tutorials/generating_stubs/using_protoc.md`)


    layout: default title: Generating stubs using protoc nav_order: 1 parent: Generating stubs grand_parent: Tutorials

    Generating stubs using protoc

    Here's an example of what a protoc command might look like to generate Go stubs, assuming that you're at the root of your repository and you have your proto files in a directory called proto:

    sh
    $ protoc -I ./proto \
       --go_out ./proto --go_opt paths=source_relative \
       --go-grpc_out ./proto --go-grpc_opt paths=source_relative \
       ./proto/helloworld/hello_world.proto

    We use the go and go-grpc plugins to generate Go types and gRPC service definitions. We're outputting the generated files relative to the proto folder, and we're using the paths=source_relative option, which means that the generated files will appear in the same directory as the source .proto file.

    This will have generated a *.pb.go and a *_grpc.pb.go file for proto/helloworld/hello_world.proto.

    Next{: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }


    --- METRICS ---