GRPC Gateway

Enable grpc-gateway.


In traditional way, we need to add a bunch of codes in order to enable grpc-gateway,

With bootstrapper, grpc-gateway will be automatically started and bind to one single port with grpc for convenience.

Steps to enable grpc-gateway:

  1. Write gw_mapping.yaml
  2. Write buf.yaml & buf.gen.yaml
  3. Generate gateway file based on gw_mapping.yaml
  4. Register gateway function into GRPC server


Install required tools.

We recommend use rk install them easily.

# Install RK CLI
$ go get -u

# List available installation
$ rk install
    buf                      install buf on local machine
    cfssl                    install cfssl on local machine
    cfssljson                install cfssljson on local machine
    gocov                    install gocov on local machine
    golangci-lint            install golangci-lint on local machine
    mockgen                  install mockgen on local machine
    pkger                    install pkger on local machine
    protobuf                 install protobuf on local machine
    protoc-gen-doc           install protoc-gen-doc on local machine
    protoc-gen-go            install protoc-gen-go on local machine
    protoc-gen-go-grpc       install protoc-gen-go-grpc on local machne
    protoc-gen-grpc-gateway  install protoc-gen-grpc-gateway on local machine
    protoc-gen-openapiv2     install protoc-gen-openapiv2 on local machine
    swag                     install swag on local machine
    rk-std                   install rk standard environment on local machine
    help, h                  Shows a list of commands or help for one command

# Install buf, protoc-gen-go, protoc-gen-go-grpc, protoc-gen-grpc-gateway, protoc-gen-openapiv2
$ rk install protoc-gen-go
$ rk install protoc-gen-go-grpc
$ rk install protoc-gen-go-grpc-gateway
$ rk install protoc-gen-openapiv2
$ rk install buf
Tool Description Installation
protobuf protocol buffer Install
buf Help you create consistent Protobuf APIs that preserve compatibility and comply with design best-practices. Install
protoc-gen-go Plugin for the Google protocol buffer compiler to generate Go code.. Install
protoc-gen-go-grpc This project aims to provide that HTTP+JSON interface to your gRPC service. Install
protoc-gen-grpc-gateway plugin for Google protocol buffer compiler to generate a reverse-proxy, which converts incoming RESTful HTTP/1 requests gRPC invocation. Install
protoc-gen-openapiv2 plugin for Google protocol buffer compiler to generate open API config file. Install


go get

General options

These are general options to start a grpc server with rk-boot

name description type default value Required The name of grpc server string “”, server won’t start Required
grpc.port The port of grpc server integer 0, server won’t start Required
grpc.enabled Enable grpc entry bool false Required
grpc.description Description of grpc entry. string "" Optional
grpc.enableReflection Enable grpc server reflection boolean false Optional
grpc.enableRkGwOption Enable RK style gateway server options. boolean false Optional
grpc.noRecvMsgSizeLimit Disable grpc server side receive message size limit boolean false Optional
grpc.gwMappingFilePaths The grpc gateway mapping file path []string [] Optional

Quick start

1.Create api/v1/greeter.proto

syntax = "proto3";

package api.v1;

option go_package = "api/v1/greeter";

service Greeter {
  rpc Greeter (GreeterRequest) returns (GreeterResponse) {}

message GreeterRequest {
  string name = 1;

message GreeterResponse {
  string message = 1;

2.Create api/v1/gw_mapping.yaml

type: google.api.Service
config_version: 3

# Please refer google.api.Http in file for details.
    - selector: api.v1.Greeter.Greeter
      get: /api/v1/greeter

3.Create buf.yaml

version: v1beta1
    - api

4.Create buf.gen.yaml

version: v1beta1
  # protoc-gen-go needs to be installed, generate go files based on proto files
  - name: go
    out: api/gen
     - paths=source_relative
  # protoc-gen-go-grpc needs to be installed, generate grpc go files based on proto files
  - name: go-grpc
    out: api/gen
      - paths=source_relative
      - require_unimplemented_servers=false
  # protoc-gen-grpc-gateway needs to be installed, generate grpc-gateway go files based on proto files
  - name: grpc-gateway
    out: api/gen
      - paths=source_relative
      - grpc_api_configuration=api/v1/gw_mapping.yaml
  # protoc-gen-openapiv2 needs to be installed, generate swagger config files based on proto files
  - name: openapiv2
    out: api/gen
      - grpc_api_configuration=api/v1/gw_mapping.yaml

5.Compile proto file

$ buf generate

There will be bellow files generated.

$ tree api/gen 
└── v1
    ├── greeter.pb.go
    ├── greeter.swagger.json
    └── greeter_grpc.pb.go
1 directory, 4 files

6.Create boot.yaml is not required, however, we strongly recommend specify this path since bootstrapper will use this in bellow:

  1. /rk/v1/apis
  2. RK TV
  - name: greeter                   # Name of grpc entry
    port: 8080                      # Port of grpc entry
    enabled: true                   # Enable grpc entry
      - "api/v1/gw_mapping.yaml"    # Boot will look for gateway mapping files and load information into memory

7. Create main.go

package main

import (

// Application entrance.
func main() {
	// Create a new boot instance.
	boot := rkboot.NewBoot()

    // ***************************************
    // ******* Register GRPC & Gateway *******
    // ***************************************

	// Get grpc entry with name
	grpcEntry := boot.GetGrpcEntry("greeter")
    // Register grpc registration function
    // Register grpc-gateway registration function

	// Bootstrap

	// Wait for shutdown sig

// Implementation of [type GrpcRegFunc func(server *grpc.Server)]
func registerGreeter(server *grpc.Server) {
	greeter.RegisterGreeterServer(server, &GreeterServer{})

// Implementation of grpc service defined in proto file
type GreeterServer struct{}

func (server *GreeterServer) Greeter(ctx context.Context, request *greeter.GreeterRequest) (*greeter.GreeterResponse, error) {
	return &greeter.GreeterResponse{
		Message: fmt.Sprintf("Hello %s!", request.Name),
	}, nil

8.Full structure

$ tree
├── api
│   ├── gen
│   │   └── v1
│   │       ├── greeter.pb.go
│   │       ├──
│   │       ├── greeter.swagger.json
│   │       └── greeter_grpc.pb.go
│   └── v1
│       ├── greeter.proto
│       └── gw_mapping.yaml
├── boot.yaml
├── buf.gen.yaml
├── buf.yaml
├── go.mod
├── go.sum
└── main.go

4 directories, 12 files


$ go run main.go
$ curl "localhost:8080/api/v1/greeter?name=rk-dev"
{"message":"Hello rk-dev!"}


Gateway server option

RK introduced gateway server options with bellow functionality.


Functionality Description
HttpErrorHandler Mainly copied from original gateway error handler. RK wrap errors to RK style error response.
MarshallerOption protojson.MarshalOptions{UseProtoNames: false, EmitUnpopulated: true},UnmarshalOptions: protojson.UnmarshalOptions{}}
Metadata Inject x-forwarded-method, x-forwarded-path, x-forwarded-scheme, x-forwarded-user-agent and x-forwarded-remote-addr into grpc metadata
OutgoingHeaderMatcher Bypass all grpc metadata to http header without prefix
IncomingHeaderMatcher Bypass all http header to grpc metadata without prefix

1.Enable rkServerOption

  - name: greeter                   # Name of grpc entry
    port: 8080                      # Port of grpc entry
    enabled: true                   # Enable grpc entry
    enableRkGwOption: true          # Enable rk style grpc gateway server option
      - "api/v1/gw_mapping.yaml"    # Bootstrapper will look for gateway mapping files and load information into memory
        enabled: true               # Enable logging interceptor for validation

2.Validate log

$ curl "localhost:8080/api/v1/greeter?name=rk-dev"

gwMethod, gwPath, gwScheme, gwUserAgent would be logged


3.Validate incoming metadata

func (server *GreeterServer) Greeter(ctx context.Context, request *greeter.GreeterRequest) (*greeter.GreeterResponse, error) {
    // Print incoming headers

	return &greeter.GreeterResponse{
		Message: fmt.Sprintf("Hello %s!", request.Name),
	}, nil
map[:authority:[] accept:[*/*] content-type:[application/grpc] user-agent:[grpc-go/1.38.0] x-forwarded-for:[::1] x-forwarded-host:[localhost:8080] x-forwarded-method:[GET] x-forwarded-path:[/v1/greeter] x-forwarded-remote-addr:[[::1]:57082] x-forwarded-scheme:[http] x-forwarded-user-agent:[curl/7.64.1]]

4.Override gateway server option for marshaller

In some cases, we may hope to override marshaller options. For example, returning underscore style restful result instead of camelcase.

Please refer to bellow repository for detailed explanations.

  - name: greeter                                     # Required
    port: 8080                                        # Required
    enabled: true                                     # Required
    enableRkGwOption: true                            # Optional, default: false
    gwOption:                                         # Optional, default: nil
      marshal:                                        # Optional, default: nil
        multiline: false                              # Optional, default: false
        emitUnpopulated: false                        # Optional, default: false
        indent: ""                                    # Optional, default: false
        allowPartial: false                           # Optional, default: false
        useProtoNames: false                          # Optional, default: false
        useEnumNumbers: false                         # Optional, default: false
      unmarshal:                                      # Optional, default: nil
        allowPartial: false                           # Optional, default: false
        discardUnknown: false                         # Optional, default: false


Error mapping

It is important to understand grpc-gateway error to grpc error mapping.

Here is the default error mapping defind in grpc-gateway.

GRPC Error GRPC Error Str Gateway(Http) Error Code Gateway(Http) Error Str
0 OK 200 OK
1 CANCELLED 408 Request Timeout
2 UNKNOWN 500 Internal Server Error
3 INVALID_ARGUMENT 400 Bad Request
4 DEADLINE_EXCEEDED 504 Gateway Timeout
5 NOT_FOUND 404 Not Found
6 ALREADY_EXISTS 409 Conflict
8 RESOURCE_EXHAUSTED 429 Too Many Requests
10 ABORTED 409 Conflict
11 OUT_OF_RANGE 400 Bad Request
12 UNIMPLEMENTED 501 Not Implemented
13 INTERNAL 500 Internal Server Error
14 UNAVAILABLE 503 Service Unavailable
15 DATA_LOSS 500 Internal Server Error
16 UNAUTHENTICATED 401 Unauthorized

1.Validate error(Standard go error)

Based on default error mapping, we expect 500 response code.

func (server *GreeterServer) Greeter(ctx context.Context, request *greeter.GreeterRequest) (*greeter.GreeterResponse, error) {
	return nil, errors.New("error triggered manually")
$ curl "localhost:8080/v1/greeter?name=rk-dev"
        "status":"Internal Server Error",
        "message":"error triggered manually",

2.Validate error(grpc error)

grpc needs to specify errors with status.New().

We recommend use rkerror to generate errors as bellow.

func (server *GreeterServer) Greeter(ctx context.Context, request *greeter.GreeterRequest) (*greeter.GreeterResponse, error) {
	return nil, rkerror.PermissionDenied("permission denied manually").Err()
curl "localhost:8080/v1/greeter?name=rk-dev"
        "message":"permission denied manually",
                "message":"[from-grpc] permission denied manually"


Last modified November 18, 2021 : Add gzip middleware documentation (f4783cb)