github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/README.md (about) 1 <div align="center"> 2 <h1>gRPC-Gateway</h1> 3 <p> 4 gRPC to JSON proxy generator following the gRPC HTTP spec 5 </p> 6 <a href="https://github.com/grpc-ecosystem/grpc-gateway/actions/workflows/main.yml"><img src="https://img.shields.io/github/workflow/status/grpc-ecosystem/grpc-gateway/main?color=379c9c&label=build&logo=github&logoColor=ffffff&style=flat-square"/></a> 7 <a href="https://app.slack.com/client/T029RQSE6/CBATURP1D"><img src="https://img.shields.io/badge/slack-grpc--gateway-379c9c?logo=slack&logoColor=ffffff&style=flat-square"/></a> 8 <a href="https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE"><img src="https://img.shields.io/github/license/grpc-ecosystem/grpc-gateway?color=379c9c&style=flat-square"/></a> 9 <a href="https://github.com/grpc-ecosystem/grpc-gateway/releases"><img src="https://img.shields.io/github/v/release/grpc-ecosystem/grpc-gateway?color=379c9c&logoColor=ffffff&style=flat-square"/></a> 10 <a href="https://github.com/grpc-ecosystem/grpc-gateway/stargazers"><img src="https://img.shields.io/github/stars/grpc-ecosystem/grpc-gateway?color=379c9c&style=flat-square"/></a> 11 <a href="https://slsa.dev/images/gh-badge-level3.svg"><img src="https://slsa.dev/images/gh-badge-level3.svg"/></a> 12 13 </div> 14 15 ## About 16 17 The gRPC-Gateway is a plugin of the Google protocol buffers compiler 18 [protoc](https://github.com/protocolbuffers/protobuf). 19 It reads protobuf service definitions and generates a reverse-proxy server which 20 translates a RESTful HTTP API into gRPC. This server is generated according to the 21 [`google.api.http`](https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L46) 22 annotations in your service definitions. 23 24 This helps you provide your APIs in both gRPC and RESTful style at the same time. 25 26 <div align="center"> 27 <img src="docs/assets/images/architecture_introduction_diagram.svg" /> 28 </div> 29 30 ## Docs 31 32 You can read our docs at: 33 34 - https://grpc-ecosystem.github.io/grpc-gateway/ 35 36 ## Testimonials 37 38 > We use the gRPC-Gateway to serve millions of API requests per day, 39 > and have been since 2018 and through all of that, 40 > we have never had any issues with it. 41 > 42 > _- William Mill, [Ad Hoc](http://adhocteam.us/)_ 43 44 ## Background 45 46 gRPC is great -- it generates API clients and server stubs in many programming 47 languages, it is fast, easy-to-use, bandwidth-efficient and its design is 48 combat-proven by Google. However, you might still want to provide a traditional 49 RESTful JSON API as well. Reasons can range from maintaining 50 backward-compatibility, supporting languages or clients that are not well supported by 51 gRPC, to simply maintaining the aesthetics and tooling involved with a RESTful 52 JSON architecture. 53 54 This project aims to provide that HTTP+JSON interface to your gRPC service. 55 A small amount of configuration in your service to attach HTTP semantics is all 56 that's needed to generate a reverse-proxy with this library. 57 58 ## Installation 59 60 ### Compile from source 61 62 The following instructions assume you are using 63 [Go Modules](https://github.com/golang/go/wiki/Modules) for dependency 64 management. Use a 65 [tool dependency](https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module) 66 to track the versions of the following executable packages: 67 68 ```go 69 // +build tools 70 71 package tools 72 73 import ( 74 _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway" 75 _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2" 76 _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" 77 _ "google.golang.org/protobuf/cmd/protoc-gen-go" 78 ) 79 ``` 80 81 Run `go mod tidy` to resolve the versions. Install by running 82 83 ```sh 84 $ go install \ 85 github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \ 86 github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \ 87 google.golang.org/protobuf/cmd/protoc-gen-go \ 88 google.golang.org/grpc/cmd/protoc-gen-go-grpc 89 ``` 90 91 This will place four binaries in your `$GOBIN`; 92 93 - `protoc-gen-grpc-gateway` 94 - `protoc-gen-openapiv2` 95 - `protoc-gen-go` 96 - `protoc-gen-go-grpc` 97 98 Make sure that your `$GOBIN` is in your `$PATH`. 99 100 ### Download the binaries 101 102 You may alternatively download the binaries from the [GitHub releases page](https://github.com/grpc-ecosystem/grpc-gateway/releases/latest). 103 We generate [SLSA3 signatures](slsa.dev) using the OpenSSF's [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) during the release process. To verify a release binary: 104 105 1. Install the verification tool from [slsa-framework/slsa-verifier#installation](https://github.com/slsa-framework/slsa-verifier#installation). 106 2. Download the provenance file `attestation.intoto.jsonl` from the [GitHub releases page](https://github.com/grpc-ecosystem/grpc-gateway/releases/latest). 107 3. Run the verifier: 108 109 ```shell 110 slsa-verifier -artifact-path <the-binary> -provenance attestation.intoto.jsonl -source github.com/grpc-ecosystem/grpc-gateway -tag <the-tag> 111 ``` 112 113 Alternatively, see the section on remotely managed plugin versions below. 114 115 ## Usage 116 117 ### 1.Define your [gRPC](https://grpc.io/docs/) service using protocol buffers 118 119 `your_service.proto`: 120 121 ```protobuf 122 syntax = "proto3"; 123 package your.service.v1; 124 option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1"; 125 126 message StringMessage { 127 string value = 1; 128 } 129 130 service YourService { 131 rpc Echo(StringMessage) returns (StringMessage) {} 132 } 133 ``` 134 135 ### 2. Generate gRPC stubs 136 137 This step generates the gRPC stubs that you can use to implement the service and consume from clients: 138 139 Here's an example `buf.gen.yaml` you can use to generate the stubs with [buf](https://github.com/bufbuild/buf): 140 141 ```yaml 142 version: v1 143 plugins: 144 - plugin: go 145 out: gen/go 146 opt: 147 - paths=source_relative 148 - plugin: go-grpc 149 out: gen/go 150 opt: 151 - paths=source_relative 152 ``` 153 154 With this file in place, you can generate your files using `buf generate`. 155 156 > For a complete example of using `buf generate` to generate protobuf stubs, see 157 > [the boilerplate repo](https://github.com/johanbrandhorst/grpc-gateway-boilerplate). 158 > For more information on generating the stubs with buf, see 159 > [the official documentation](https://docs.buf.build/generate-usage). 160 161 If you are using `protoc` to generate stubs, here's an example of what a command 162 might look like: 163 164 ```sh 165 protoc -I . \ 166 --go_out ./gen/go/ --go_opt paths=source_relative \ 167 --go-grpc_out ./gen/go/ --go-grpc_opt paths=source_relative \ 168 your/service/v1/your_service.proto 169 ``` 170 171 ### 3. Implement your service in gRPC as usual. 172 173 ### 4. Generate reverse-proxy using `protoc-gen-grpc-gateway` 174 175 At this point, you have 3 options: 176 177 - no further modifications, use the default mapping to HTTP semantics (method, path, etc.) 178 - this will work on any `.proto` file, but will not allow setting HTTP paths, request parameters or similar 179 - additional `.proto` modifications to use a custom mapping 180 - relies on parameters in the `.proto` file to set custom HTTP mappings 181 - no `.proto` modifications, but use an external configuration file 182 - relies on an external configuration file to set custom HTTP mappings 183 - mostly useful when the source proto file isn't under your control 184 185 #### 1. Using the default mapping 186 187 This requires no additional modification to the `.proto` file but does require enabling a specific option when executing the plugin. 188 The `generate_unbound_methods` should be enabled. 189 190 Here's what a `buf.gen.yaml` file might look like with this option enabled: 191 192 ```yaml 193 version: v1 194 plugins: 195 - plugin: go 196 out: gen/go 197 opt: 198 - paths=source_relative 199 - plugin: go-grpc 200 out: gen/go 201 opt: 202 - paths=source_relative 203 - plugin: grpc-gateway 204 out: gen/go 205 opt: 206 - paths=source_relative 207 - generate_unbound_methods=true 208 ``` 209 210 With `protoc` (just the grpc-gateway stubs): 211 212 ```sh 213 protoc -I . --grpc-gateway_out ./gen/go \ 214 --grpc-gateway_opt paths=source_relative \ 215 --grpc-gateway_opt generate_unbound_methods=true \ 216 your/service/v1/your_service.proto 217 ``` 218 219 #### 2. With custom annotations 220 221 Add a [`google.api.http`](https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L46) 222 annotation to your .proto file 223 224 `your_service.proto`: 225 226 ```diff 227 syntax = "proto3"; 228 package your.service.v1; 229 option go_package = "github.com/yourorg/yourprotos/gen/go/your/service/v1"; 230 + 231 +import "google/api/annotations.proto"; 232 + 233 message StringMessage { 234 string value = 1; 235 } 236 237 service YourService { 238 - rpc Echo(StringMessage) returns (StringMessage) {} 239 + rpc Echo(StringMessage) returns (StringMessage) { 240 + option (google.api.http) = { 241 + post: "/v1/example/echo" 242 + body: "*" 243 + }; 244 + } 245 } 246 ``` 247 248 > You will need to provide the required third party protobuf files to the protobuf compiler. 249 > If you are using [buf](https://github.com/bufbuild/buf), this dependency can 250 > be added to the `deps` array in your `buf.yaml` under the name 251 > `buf.build/googleapis/googleapis`: 252 > 253 > ```yaml 254 > version: v1 255 > name: buf.build/yourorg/myprotos 256 > deps: 257 > - buf.build/googleapis/googleapis 258 > ``` 259 > 260 > Always run `buf mod update` after adding a dependency to your `buf.yaml`. 261 262 See [a_bit_of_everything.proto](examples/internal/proto/examplepb/a_bit_of_everything.proto) 263 for examples of more annotations you can add to customize gateway behavior 264 and generated OpenAPI output. 265 266 Here's what a `buf.gen.yaml` file might look like: 267 268 ```yaml 269 version: v1 270 plugins: 271 - plugin: go 272 out: gen/go 273 opt: 274 - paths=source_relative 275 - plugin: go-grpc 276 out: gen/go 277 opt: 278 - paths=source_relative 279 - plugin: grpc-gateway 280 out: gen/go 281 opt: 282 - paths=source_relative 283 ``` 284 285 If you are using `protoc` to generate stubs, you need to ensure the required 286 dependencies are available to the compiler at compile time. These can be found 287 by manually cloning and copying the relevant files from the 288 [googleapis repository](https://github.com/googleapis/googleapis), and providing 289 them to `protoc` when running. The files you will need are: 290 291 ``` 292 google/api/annotations.proto 293 google/api/field_behavior.proto 294 google/api/http.proto 295 google/api/httpbody.proto 296 ``` 297 298 Here's what a `protoc` execution might look like: 299 300 ```sh 301 protoc -I . --grpc-gateway_out ./gen/go \ 302 --grpc-gateway_opt paths=source_relative \ 303 your/service/v1/your_service.proto 304 ``` 305 306 #### 3. External configuration 307 308 If you do not want to (or cannot) modify the proto file for use with gRPC-Gateway you can 309 alternatively use an external 310 [gRPC Service Configuration](https://cloud.google.com/endpoints/docs/grpc/grpc-service-config) file. 311 [Check our documentation](https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/grpc_api_configuration/) 312 for more information. This is best combined with the `standalone=true` option 313 to generate a file that can live in its own package, separate from the files 314 generated by the source protobuf file. 315 316 Here's what a `buf.gen.yaml` file might look like with this option enabled: 317 318 ```yaml 319 version: v1 320 plugins: 321 - plugin: go 322 out: gen/go 323 opt: 324 - paths=source_relative 325 - plugin: go-grpc 326 out: gen/go 327 opt: 328 - paths=source_relative 329 - plugin: grpc-gateway 330 out: gen/go 331 opt: 332 - paths=source_relative 333 - grpc_api_configuration=path/to/config.yaml 334 - standalone=true 335 ``` 336 337 With `protoc` (just the grpc-gateway stubs): 338 339 ```sh 340 protoc -I . --grpc-gateway_out ./gen/go \ 341 --grpc-gateway_opt paths=source_relative \ 342 --grpc-gateway_opt grpc_api_configuration=path/to/config.yaml \ 343 --grpc-gateway_opt standalone=true \ 344 your/service/v1/your_service.proto 345 ``` 346 347 ### 5. Write an entrypoint for the HTTP reverse-proxy server 348 349 ```go 350 package main 351 352 import ( 353 "context" 354 "flag" 355 "net/http" 356 357 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 358 "google.golang.org/grpc" 359 "google.golang.org/grpc/credentials/insecure" 360 "google.golang.org/grpc/grpclog" 361 362 gw "github.com/yourorg/yourrepo/proto/gen/go/your/service/v1/your_service" // Update 363 ) 364 365 var ( 366 // command-line options: 367 // gRPC server endpoint 368 grpcServerEndpoint = flag.String("grpc-server-endpoint", "localhost:9090", "gRPC server endpoint") 369 ) 370 371 func run() error { 372 ctx := context.Background() 373 ctx, cancel := context.WithCancel(ctx) 374 defer cancel() 375 376 // Register gRPC server endpoint 377 // Note: Make sure the gRPC server is running properly and accessible 378 mux := runtime.NewServeMux() 379 opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())} 380 err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts) 381 if err != nil { 382 return err 383 } 384 385 // Start HTTP server (and proxy calls to gRPC server endpoint) 386 return http.ListenAndServe(":8081", mux) 387 } 388 389 func main() { 390 flag.Parse() 391 392 if err := run(); err != nil { 393 grpclog.Fatal(err) 394 } 395 } 396 ``` 397 398 ### 6. (Optional) Generate OpenAPI definitions using `protoc-gen-openapiv2` 399 400 Here's what a `buf.gen.yaml` file might look like: 401 402 ```yaml 403 version: v1 404 plugins: 405 - plugin: go 406 out: gen/go 407 opt: 408 - paths=source_relative 409 - plugin: go-grpc 410 out: gen/go 411 opt: 412 - paths=source_relative 413 - plugin: grpc-gateway 414 out: gen/go 415 opt: 416 - paths=source_relative 417 - plugin: openapiv2 418 out: gen/openapiv2 419 ``` 420 421 To use the custom protobuf annotations supported by `protoc-gen-openapiv2`, we need 422 another dependency added to our protobuf generation step. If you are using 423 `buf`, you can add the `buf.build/grpc-ecosystem/grpc-gateway` dependency 424 to your `deps` array: 425 426 ```yaml 427 version: v1 428 name: buf.build/yourorg/myprotos 429 deps: 430 - buf.build/googleapis/googleapis 431 - buf.build/grpc-ecosystem/grpc-gateway 432 ``` 433 434 With `protoc` (just the swagger file): 435 436 ```sh 437 protoc -I . --openapiv2_out ./gen/openapiv2 \ 438 your/service/v1/your_service.proto 439 ``` 440 441 If you are using `protoc` to generate stubs, you will need to copy the protobuf 442 files from the `protoc-gen-openapiv2/options` directory of this repository, 443 and providing them to `protoc` when running. 444 445 Note that this plugin also supports generating OpenAPI definitions for unannotated methods; 446 use the `generate_unbound_methods` option to enable this. 447 448 It is possible with the HTTP mapping for a gRPC service method to create duplicate mappings 449 with the only difference being constraints on the path parameter. 450 451 `/v1/{name=projects/*}` and `/v1/{name=organizations/*}` both become `/v1/{name}`. When 452 this occurs the plugin will rename the path parameter with a "\_1" (or "\_2" etc) suffix 453 to differentiate the different operations. So in the above example, the 2nd path would become 454 `/v1/{name_1=organizations/*}`. This can also cause OpenAPI clients to URL encode the "/" that is 455 part of the path parameter as that is what OpenAPI defines in the specification. To allow gRPC gateway to 456 accept the URL encoded slash and still route the request, use the UnescapingModeAllCharacters or 457 UnescapingModeLegacy (which is the default currently though may change in future versions). See 458 [Customizing Your Gateway](https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/customizing_your_gateway/) 459 for more information. 460 461 ## Usage with remote plugins 462 463 As an alternative to all of the above, you can use `buf` with 464 [remote plugins](https://docs.buf.build/configuration/v1/buf-gen-yaml#name-or-remote) 465 to manage plugin versions and generation. An example `buf.gen.yaml` using remote 466 plugin generation looks like this: 467 468 ```yaml 469 version: v1 470 plugins: 471 - plugin: buf.build/protocolbuffers/go:v1.31.0 472 out: gen/go 473 opt: 474 - paths=source_relative 475 - plugin: buf.build/grpc/go:v1.3.0 476 out: gen/go 477 opt: 478 - paths=source_relative 479 - plugin: buf.build/grpc-ecosystem/gateway:v2.16.2 480 out: gen/go 481 opt: 482 - paths=source_relative 483 - plugin: buf.build/grpc-ecosystem/openapiv2:v2.16.2 484 out: gen/openapiv2 485 ``` 486 487 This requires no local installation of any plugins. Be careful to use the same 488 version of the generator as the runtime library, i.e. if using `v2.16.2`, run 489 490 ```shell 491 $ go get github.com/grpc-ecosystem/grpc-gateway/v2@v2.16.2 492 ``` 493 494 To get the same version of the runtime in your `go.mod`. 495 496 Note that usage of remote plugins is incompatible with usage of external configuration files like [grpc_api_configuration](https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/grpc_api_configuration/#using-an-external-configuration-file). 497 498 ## Video intro 499 500 This GopherCon UK 2019 presentation from our maintainer [@JohanBrandhorst](https://github.com/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. 501 502 <div align="center"> 503 <a href="https://www.youtube.com/watch?v=Pq1paKC-fXk"> 504 <img src="https://img.youtube.com/vi/Pq1paKC-fXk/0.jpg" /> 505 </a> 506 </div> 507 508 ## Parameters and flags 509 510 When using `buf` to generate stubs, flags and parameters are passed through 511 the `opt` field in your `buf.gen.yaml` file, for example: 512 513 ```yaml 514 version: v1 515 plugins: 516 - plugin: grpc-gateway 517 out: gen/go 518 opt: 519 - paths=source_relative 520 - grpc_api_configuration=path/to/config.yaml 521 - standalone=true 522 ``` 523 524 During code generation with `protoc`, flags to gRPC-Gateway tools must be passed 525 through `protoc` using one of 2 patterns: 526 527 - as part of the `--<tool_suffix>_out` `protoc` parameter: `--<tool_suffix>_out=<flags>:<path>` 528 529 ```sh 530 --grpc-gateway_out=repeated_path_param_separator=ssv:. 531 --openapiv2_out=repeated_path_param_separator=ssv:. 532 ``` 533 534 - using additional `--<tool_suffix>_opt` parameters: `--<tool_suffix>_opt=<flag>[,<flag>]*` 535 536 ```sh 537 --grpc-gateway_opt repeated_path_param_separator=ssv 538 --openapiv2_opt repeated_path_param_separator=ssv 539 ``` 540 541 ## More examples 542 543 More examples are available under the `examples` directory. 544 545 - `proto/examplepb/echo_service.proto`, `proto/examplepb/a_bit_of_everything.proto`, `proto/examplepb/unannotated_echo_service.proto`: service definition 546 - `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 547 - `proto/examplepb/echo_service.pb.gw.go`, `proto/examplepb/a_bit_of_everything.pb.gw.go`, `proto/examplepb/uannotated_echo_service.pb.gw.go`: [generated] reverse proxy for the service 548 - `proto/examplepb/unannotated_echo_service.yaml`: gRPC API Configuration for `unannotated_echo_service.proto` 549 - `server/main.go`: service implementation 550 - `main.go`: entrypoint of the generated reverse proxy 551 552 To use the same port for custom HTTP handlers (e.g. serving `swagger.json`), 553 gRPC-Gateway, and a gRPC server, see 554 [this example by CoreOS](https://github.com/philips/grpc-gateway-example/blob/master/cmd/serve.go) 555 (and its accompanying [blog post](https://web.archive.org/web/20201112010739/https://coreos.com/blog/grpc-protobufs-swagger.html)). 556 557 [This example by neiro.ai](https://github.com/mynalabsai/grpc_gateway_media_example) (and its accompanying [blog post](https://medium.com/neiro-ai/grpc-gateway-for-media-api-by-neiro-9033caab12c8)) shows how mediafiles using `multipart/form-data` can be integrated into rpc messages using a middleware. 558 559 ## Features 560 561 ### Supported 562 563 - Generating JSON API handlers. 564 - Method parameters in the request body. 565 - Method parameters in the request path. 566 - Method parameters in the query string. 567 - Enum fields in the path parameter (including repeated enum fields). 568 - Mapping streaming APIs to newline-delimited JSON streams. 569 - Mapping HTTP headers with `Grpc-Metadata-` prefix to gRPC metadata (prefixed with `grpcgateway-`) 570 - Optionally emitting API definitions for 571 [OpenAPI (Swagger) v2](https://swagger.io/docs/specification/2-0/basic-structure/). 572 - Setting [gRPC timeouts](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests) 573 through inbound HTTP `Grpc-Timeout` header. 574 - Partial support for [gRPC API Configuration](https://cloud.google.com/endpoints/docs/grpc/grpc-service-config) 575 files as an alternative to annotation. 576 - Automatically translating PATCH requests into Field Mask gRPC requests. See 577 [the docs](https://grpc-ecosystem.github.io/grpc-gateway/docs/mapping/patch_feature/) 578 for more information. 579 580 ### No plan to support 581 582 But patches are welcome. 583 584 - Method parameters in HTTP headers. 585 - Handling trailer metadata. 586 - Encoding request/response body in XML. 587 - True bi-directional streaming. 588 589 ## Mapping gRPC to HTTP 590 591 - [How gRPC error codes map to HTTP status codes in the response](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/runtime/errors.go#L15). 592 - HTTP request source IP is added as `X-Forwarded-For` gRPC request header. 593 - HTTP request host is added as `X-Forwarded-Host` gRPC request header. 594 - HTTP `Authorization` header is added as `authorization` gRPC request header. 595 - Remaining Permanent HTTP header keys (as specified by the IANA 596 [here](http://www.iana.org/assignments/message-headers/message-headers.xhtml)) 597 are prefixed with `grpcgateway-` and added with their values to gRPC request 598 header. 599 - HTTP headers that start with 'Grpc-Metadata-' are mapped to gRPC metadata 600 (prefixed with `grpcgateway-`). 601 - While configurable, the default {un,}marshaling uses 602 [protojson](https://pkg.go.dev/google.golang.org/protobuf/encoding/protojson). 603 - The path template used to map gRPC service methods to HTTP endpoints supports the [google.api.http](https://github.com/googleapis/googleapis/blob/master/google/api/http.proto) 604 path template syntax. For example, `/api/v1/{name=projects/*/topics/*}` or `/prefix/{path=organizations/**}`. 605 606 ## Contribution 607 608 See [CONTRIBUTING.md](http://github.com/grpc-ecosystem/grpc-gateway/blob/main/CONTRIBUTING.md). 609 610 ## License 611 612 gRPC-Gateway is licensed under the BSD 3-Clause License. 613 See [LICENSE](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/LICENSE) for more details.