gRPC gateway

Overview

With the prevalence of the microservice architecture, the gRPC framework is widely used as a high-performance, cross-language remote process call (RPC).However, gRPC does not apply to all application scenarios.For example, when the client does not support a gRPC protocol or needs to expose the gRPC service to a web application, a way to convert the RESTful API to a gRPC.The gRPC gateway should therefore be created.

Implementation in gRPC brokered go-Zero

The gRPC gateway in go-Zero is a HTTP server that converts RESTful API into a gRPC request and converts gRPC response to RESTful API.The process is as follows::

  1. Resolves the definition of a gRPC service from proto file.
  2. Resolve HTTP mapping rules for gRPC services from the configuration file.
  3. Generate HTTP processor for gRPC services based on the definition of a gRPC service and HTTP mapping rules.
  4. Start HTTP server, handle HTTP requests.
  5. Convert HTTP request to a gRPC request.
  6. Convert gRPC response to HTTP response.
  7. Return HTTP response.

Details can be consulted gateway.

Configure Introduction

  1. type (
  2. GatewayConf struct {
  3. rest.RestConf
  4. Upstreams []Upstream
  5. Timeout time.Duration `json:",default=5s"`
  6. }
  7. RouteMapping struct {
  8. Method string
  9. Path string
  10. RpcPath string
  11. }
  12. Upstream struct {
  13. Name string `json:",optional"`
  14. Grpc zrpc.RpcClientConf
  15. ProtoSets []string `json:",optional"`
  16. Mappings []RouteMapping `json:",optional"`
  17. }
  18. )

GatewayConf

gRPC gateway - 图1NameNoteDataTypeRequired?Sample
RestConfrest Service ConfigurationRestConfYESReferenceBasic Service Configuration
UpstreamsgRPC Service Configuration[]UpstreamYES
TimeoutTimeout timedurationNO5s

Upstream

gRPC gateway - 图2NameNoteDataTypeRequired?Sample
NameService NamestringNOdemo1-gateway
GrpcgRPC Service ConfigurationRpcClientConfYESReferenceRPC configuration
ProtoSetsproto file list[]stringNO[“hello.pb”]
MappingsRoute mapping, do not fill by default all grpc paths[]RouteMappingNO

RouteMapping

gRPC gateway - 图3NameNoteDataTypeRequired?Sample
MethodHTTP methodsstringYESget
PathHTTP PathstringYES/ping
RpcPathgRPC PathstringYEShello.Hello/Ping

Examples

In go-zero, there are two ways to use gRPC gateways: protoDescriptor and grpcReflection.

  • protoDescriptor
  • grpcReflection

protoDescriptor method requires proto to be a pb file via protoc and then reference the pb file to rest-grpc rule in gateway.

gRPC gateway - 图4tip

go-zero sdk version v1.5.0 gateway configuration will cause configuration conflicts, please avoid this version, the current example is using v1.4.4 version

  1. We create a new project, demo1, and a new hello.proto file in demo1, as follows:
  1. syntax = "proto3";
  2. package hello;
  3. option go_package = "./hello";
  4. message Request {
  5. }
  6. message Response {
  7. string msg = 1;
  8. }
  9. service Hello {
  10. rpc Ping(Request) returns(Response);
  11. }
  1. Create the gateway directory in the demo1 directory, and then execute the following command in the demo1 directory to generate the protoDescriptor:
  1. $ protoc --descriptor_set_out=gateway/hello.pb hello.proto
  1. Generate the grpc service code by executing the following command in the demo1 directory:
  1. $ goctl rpc protoc hello.proto --go_out=server --go-grpc_out=server --zrpc_out=server

Populate the logic for the Ping method in demo1/server/internal/logic/pinglogic.go with the following code:

  1. func (l *PingLogic) Ping(in *hello.Request) (*hello.Response, error) {
  2. return &hello.Response{
  3. Msg: "pong",
  4. }, nil
  5. }
  1. Modify the configuration file demo1/server/etc/hello.yaml to read as follows:
  1. Name: hello.rpc
  2. ListenOn: 0.0.0.0:8080
  1. Go to the demo1/gateway directory, create the directory etc, and add the configuration file gateway.yaml, as follows:
  1. Name: demo1-gateway
  2. Host: localhost
  3. Port: 8888
  4. Upstreams:
  5. - Grpc:
  6. Target: 0.0.0.0:8080
  7. # protoset mode
  8. ProtoSets:
  9. - hello.pb
  10. # Mappings can also be written in proto options
  11. Mappings:
  12. - Method: get
  13. Path: /ping
  14. RpcPath: hello.Hello/Ping
  1. Go to the demo1/gateway directory and create a new gateway.go file with the following contents:
  1. package main
  2. import (
  3. "flag"
  4. "github.com/zeromicro/go-zero/core/conf"
  5. "github.com/zeromicro/go-zero/gateway"
  6. )
  7. var configFile = flag.String("f", "etc/gateway.yaml", "config file")
  8. func main() {
  9. flag.Parse()
  10. var c gateway.GatewayConf
  11. conf.MustLoad(*configFile, &c)
  12. gw := gateway.MustNewServer(c)
  13. defer gw.Stop()
  14. gw.Start()
  15. }
  1. Open two separate terminals to start the grpc server service and the gateway service, and then visit http://localhost:8888/ping:
  1. # Go to the demo1/server directory and start the grpc service
  2. $ go run hello.go
  3. Starting rpc server at 0.0.0.0:8080...
  1. # Go to the demo1/gateway directory and start the gateway service
  2. $ go run gateway.go
  1. # Open a new terminal and access the gateway service
  2. $ curl http://localhost:8888/ping
  3. {"msg":"pong"}%

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:
  1. syntax = "proto3";
  2. package hello;
  3. option go_package = "./hello";
  4. message Request {
  5. }
  6. message Response {
  7. string msg = 1;
  8. }
  9. service Hello {
  10. rpc Ping(Request) returns(Response);
  11. }
  1. Create a gateway directory under the demo2 directory for backup

  2. Generate the grpc service code by executing the following command in the demo2 directory:

  1. $ goctl rpc protoc hello.proto --go_out=server --go-grpc_out=server --zrpc_out=server

Populate the logic for the Ping method in demo2/server/internal/logic/pinglogic.go with the following code:

  1. func (l *PingLogic) Ping(in *hello.Request) (*hello.Response, error) {
  2. return &hello.Response{
  3. Msg: "pong",
  4. }, nil
  5. }

Modify the configuration file demo2/server/etc/hello.yaml as follows:

  1. Name: hello.rpc
  2. ListenOn: 0.0.0.0:8080
  3. Mode: dev
gRPC gateway - 图5tip

Since the grpc reflection mode is currently only supported by the dev and test environments, you need to set Mode to dev or test here.

  1. Go to the demo2/gateway directory, create the directory etc, and add the configuration file gateway.yaml, as follows:
  1. Name: demo1-gateway
  2. Host: localhost
  3. Port: 8888
  4. Upstreams:
  5. - Grpc:
  6. Target: 0.0.0.0:8080
  7. # Mappings can also be written in proto options
  8. Mappings:
  9. - Method: get
  10. Path: /ping
  11. RpcPath: hello.Hello/Ping
  1. Go to the demo2/gateway directory and create a new gateway.go file with the following contents:
  1. package main
  2. import (
  3. "flag"
  4. "github.com/zeromicro/go-zero/core/conf"
  5. "github.com/zeromicro/go-zero/gateway"
  6. )
  7. var configFile = flag.String("f", "etc/gateway.yaml", "config file")
  8. func main() {
  9. flag.Parse()
  10. var c gateway.GatewayConf
  11. conf.MustLoad(*configFile, &c)
  12. gw := gateway.MustNewServer(c)
  13. defer gw.Stop()
  14. gw.Start()
  15. }
  1. Open two separate terminals to start the grpc server service and the gateway service, and then visit http://localhost:8888/ping:
  1. # Go to the demo1/server directory and start the grpc service
  2. $ go run hello.go
  3. Starting rpc server at 0.0.0.0:8080...
  1. # Go to the demo1/gateway directory and start the gateway service
  2. $ go run gateway.go
  1. # Open a new terminal and access the gateway service
  2. $ curl http://localhost:8888/ping
  3. {"msg":"pong"}%

References