gRPC Gateway
Overview
Section titled “Overview”As microservice architectures become more common, gRPC is widely adopted as a high-performance, cross-language RPC framework. However, gRPC is not suitable for every scenario — for example, when clients do not support gRPC, or when you need to expose gRPC services to web applications via a RESTful API. In these cases, a gRPC gateway bridges the gap.
How go-zero’s gRPC Gateway Works
Section titled “How go-zero’s gRPC Gateway Works”The gRPC gateway in go-zero is an HTTP server that translates RESTful requests into gRPC calls and converts gRPC responses back to HTTP. The flow is:
- Load the gRPC service definition from a proto file.
- Load HTTP-to-gRPC mapping rules from the configuration file.
- Generate HTTP handlers for each gRPC method.
- Start the HTTP server and accept incoming requests.
- Translate each HTTP request into a gRPC request.
- Translate the gRPC response into an HTTP response.
- Return the HTTP response to the caller.
For the full gateway source, see go-zero/gateway.
Configure Introduction
Section titled “Configure Introduction”type ( GatewayConf struct { rest.RestConf Upstreams []Upstream Timeout time.Duration `json:",default=5s"` }
RouteMapping struct { Method string Path string RpcPath string }
Upstream struct { Name string `json:",optional"` Grpc zrpc.RpcClientConf ProtoSets []string `json:",optional"` Mappings []RouteMapping `json:",optional"` })GatewayConf
Section titled “GatewayConf”| Note | DataType | Required? | Sample | |
|---|---|---|---|---|
| RestConf | rest Service Configuration | RestConf | YES | See Basic Service Configuration |
| Upstreams | gRPC Service Configuration | []Upstream | YES | |
| Timeout | Timeout time | duration | NO | 5s |
Upstream
Section titled “Upstream”| Note | DataType | Required? | Sample | |
|---|---|---|---|---|
| Name | Service Name | string | NO | demo1-gateway |
| Grpc | gRPC Service Configuration | RpcClientConf | YES | See RPC configuration |
| ProtoSets | proto file list | []string | NO | ["hello.pb"] |
| Mappings | Route mapping, do not fill by default all grpc paths | []RouteMapping | NO |
RouteMapping
Section titled “RouteMapping”| Note | DataType | Required? | Sample | |
|---|---|---|---|---|
| Method | HTTP methods | string | YES | get |
| Path | HTTP Path | string | YES | /ping |
| RpcPath | gRPC Path | string | YES | hello.Hello/Ping |
Examples
Section titled “Examples”In go-zero, there are two ways to use gRPC gateways: protoDescriptor and grpcReflection.
protoDescriptor protoDescriptor method requires proto to be a pb file via protoc and then reference the pb file to rest-grpc rule in gateway.
1 We create a new project, demo1, and a new hello.proto file in demo1, as follows:
syntax = "proto3";
package hello;
option go_package = "./hello";
message Request {}
message Response { string msg = 1;}
service Hello { rpc Ping(Request) returns(Response);}2 Create the gateway directory in the demo1 directory, and then execute the following command in the demo1 directory to generate the protoDescriptor:
$ protoc --descriptor_set_out=gateway/hello.pb hello.proto3 Generate the grpc service code by executing the following command in the demo1 directory:
$ goctl rpc protoc hello.proto --go_out=server --go-grpc_out=server --zrpc_out=serverPopulate the logic for the Ping method in demo1/server/internal/logic/pinglogic.go with the following code:
func (l *PingLogic) Ping(in *hello.Request) (*hello.Response, error) { return &hello.Response{ Msg: "pong", }, nil}4 Modify the configuration file demo1/server/etc/hello.yaml to read as follows:
Name: hello.rpcListenOn: 0.0.0.0:80805 Go to the demo1/gateway directory, create the directory etc, and add the configuration file gateway.yaml, as follows:
Name: demo1-gatewayHost: localhostPort: 8888Upstreams: - Grpc: Target: localhost:8080 # protoset mode ProtoSets: - hello.pb # Mappings can also be written in proto options Mappings: - Method: get Path: /ping RpcPath: hello.Hello/Ping6 Go to the demo1/gateway directory and create a new gateway.go file with the following contents:
package main
import ( "flag"
"github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/gateway")
var configFile = flag.String("f", "etc/gateway.yaml", "config file")
func main() { flag.Parse()
var c gateway.GatewayConf conf.MustLoad(*configFile, &c) gw := gateway.MustNewServer(c) defer gw.Stop() gw.Start()}7 Open two separate terminals to start the grpc server service and the gateway service, and then visit http://localhost:8888/ping:
# Go to the demo1/server directory and start the grpc service$ go run hello.goStarting rpc server at 0.0.0.0:8080...# Go to the demo1/gateway directory and start the gateway service$ go run gateway.go# Open a new terminal and access the gateway service$ curl http://localhost:8888/ping{"msg":"pong"}%grpcReflection The grpcReflection method is similar to the protoDescriptor method. Unlike the grpcReflection method does not require proto to be produced as a pb file through protoc but takes proto from the grpc server directly and then quotes the proto file for rest-grpc rule in gateway.
1 We create a new project, demo2, and a new hello.proto file in demo2, as follows:
syntax = "proto3";
package hello;
option go_package = "./hello";
message Request {}
message Response { string msg = 1;}
service Hello { rpc Ping(Request) returns(Response);}2 Create a gateway directory under the demo2 directory for backup
3 Generate the grpc service code by executing the following command in the demo2 directory:
$ goctl rpc protoc hello.proto --go_out=server --go-grpc_out=server --zrpc_out=serverPopulate the logic for the Ping method in demo2/server/internal/logic/pinglogic.go with the following code:
func (l *PingLogic) Ping(in *hello.Request) (*hello.Response, error) { return &hello.Response{ Msg: "pong", }, nil}Modify the configuration file demo2/server/etc/hello.yaml as follows:
Name: hello.rpcListenOn: 0.0.0.0:8080Mode: dev4 Go to the demo2/gateway directory, create the directory etc, and add the configuration file gateway.yaml, as follows:
Name: demo1-gatewayHost: localhostPort: 8888Upstreams: - Grpc: Target: localhost:8080 # Mappings can also be written in proto options Mappings: - Method: get Path: /ping RpcPath: hello.Hello/Ping5 Go to the demo2/gateway directory and create a new gateway.go file with the following contents:
package main
import ( "flag"
"github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/gateway")
var configFile = flag.String("f", "etc/gateway.yaml", "config file")
func main() { flag.Parse()
var c gateway.GatewayConf conf.MustLoad(*configFile, &c) gw := gateway.MustNewServer(c) defer gw.Stop() gw.Start()}6 Open two separate terminals to start the grpc server service and the gateway service, and then visit http://localhost:8888/ping:
# Go to the demo1/server directory and start the grpc service$ go run hello.goStarting rpc server at 0.0.0.0:8080...# Go to the demo1/gateway directory and start the gateway service$ go run gateway.go# Open a new terminal and access the gateway service$ curl http://localhost:8888/ping{"msg":"pong"}%