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. }

2 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

3 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. }

4 Modify the configuration file demo1/server/etc/hello.yaml to read as follows:

  1. Name: hello.rpc
  2. ListenOn: 0.0.0.0:8080

5 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: localhost: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

6 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. }

7 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. }

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:

  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.

4 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: localhost:8080
  7. # Mappings can also be written in proto options
  8. Mappings:
  9. - Method: get
  10. Path: /ping
  11. RpcPath: hello.Hello/Ping

5 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. }

6 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