1. 程式人生 > >grpc服務整合RESFful JSON API grpc-gateway和swagger-ui介面

grpc服務整合RESFful JSON API grpc-gateway和swagger-ui介面

閱讀時間:5min左右

本文目的:

說明如何使用grpc-gateway(下圖紅色部分)反向代理外掛將RESTful JSON API轉換為gRPC,並使用swagger ui提供rest api介面。

grpc-gateway

整合步驟:

上圖所示,由下往上

一、HelloWorld gRPC服務

首先先有一個gRPC服務,我們這個服務使用java實現,並使用maven進行管理,具體細節可檢視git庫:

1.安裝所需軟體版本

安裝步驟不再展開,我相信你們可以安裝好的。

2.編寫Hello world gRPC服務

1)建立一個maven工程

最後的專案結構如下 (剛建立的專案沒有程式碼檔案,由接下來的步驟建立)

.
├── cmd
│   ├── helloworld.pb.go
│   ├── helloworld.pb.gw.go
│   ├── helloworld.swagger.go
│   └── swagger
│       └── ui
│           └── data
│               └── datafile.go
├── helloworld.swagger.json
├── java-grpc-swagger.iml
├── pom.xml
├── proxy
├── proxy.go
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── tuputech
│   │   │           └── grpc
│   │   │               ├── HelloWorldClient.java
│   │   │               └── HelloWorldServer.java
│   │   ├── proto
│   │   │   └── helloworld.proto
│   │   └── resources
│   │       └── swagger-ui
│   │           ├── favicon-16x16.png
│   │           ├── favicon-32x32.png
│   │           ├── index.html
│   │           ├── oauth2-redirect.html
│   │           ├── swagger-ui-bundle.js
│   │           ├── swagger-ui-bundle.js.map
│   │           ├── swagger-ui-standalone-preset.js
│   │           ├── swagger-ui-standalone-preset.js.map
│   │           ├── swagger-ui.css
│   │           ├── swagger-ui.css.map
│   │           ├── swagger-ui.js
│   │           └── swagger-ui.js.map
│   └── test
│       └── java

直接拷貝gRPC github上的程式碼,進行執行即可

2)拷貝gRPC的proto的檔案

helloworld.proto

https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto/helloworld.proto
3)拷貝gRPC的server和client的java程式碼

HelloWorldServer.java和HelloWorldClient.java

https://github.com/grpc/grpc-java/tree/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java

https://github.com/grpc/grpc-java/tree/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java

4)編譯直接執行

執行時日誌

Sep 17, 2018 8:57:00 PM com.tuputech.grpc.HelloWorldServer start
資訊: Server started, listening on 50051

二、RESTful JSON gRPC-gateway

1.安裝gprc-gateway

go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
go get -u github.com/golang/protobuf/protoc-gen-go

2.修改helloworld.proto檔案

新增gateway的選項

import "google/api/annotations.proto"

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      post: "/v1/hello"
      body: "*"
    };
  }
}

3.生成grpc golang stub類檔案

 protoc -I/Users/stephen/Documents/develop/java-grpc-swagger/src/main/proto/ -I. \
  -I$GOPATH/src \
  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --go_out=plugins=grpc:. \
  /Users/stephen/Documents/develop/java-grpc-swagger/src/main/proto/helloworld.proto

對應生成helloworld.pb.go檔案

4.生成反向代理程式碼

  protoc -I/Users/stephen/Documents/develop/java-grpc-swagger/src/main/proto/ -I. \
  -I$GOPATH/src \
  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --plugin=protoc-gen-grpc=grpc_ruby_plugin \
  --grpc-gateway_out=logtostderr=true:. \
  /Users/stephen/Documents/develop/java-grpc-swagger/src/main/proto/helloworld.proto

對應生成helloworld.pb.gw.go

把以上生成的go檔案移到cmd的資料夾下面

5.編寫proxy.go

package main

import (
    "flag"
    "log"
    "net/http"

    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "golang.org/x/net/context"
    "google.golang.org/grpc"

    gw "../java-grpc-swagger/cmd"
)

var (
    greeterEndpoint = flag.String("helloworld_endpoint", "localhost:50051", "endpoint of Greeter gRPC Service")
)

func run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux := runtime.NewServeMux()
    opts := []grpc.DialOption{grpc.WithInsecure()}
    err := gw.RegisterGreeterHandlerFromEndpoint(ctx, mux, *greeterEndpoint, opts)
    if err != nil {
        return err
    }

    log.Print("Greeter gRPC Server gateway start at port 8080...")
    http.ListenAndServe(":8080", mux)
    return nil
}

func main() {
    flag.Parse()

    if err := run(); err != nil {
        log.Fatal(err)
    }
}

編譯生成可執行檔案proxy

go build proxy.go

6.啟動服務

1)啟動grpc服務
Sep 18, 2018 10:51:35 AM com.tuputech.grpc.HelloWorldServer start
資訊: Server started, listening on 50051
2)啟動RESTful JSON API gateway
➜  java-grpc-swagger proxy
2018/09/18 10:27:57 Greeter gRPC Server gateway start at port 8080...

3)使用curl訪問
➜  ~ curl -X POST "http://localhost:8080/v1/hello" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"name\": \"string\"}"
{"message":"Hello string"}%

三、整合swagger-ui

1.生成RESTful JSON API的Swagger說明

  protoc -I/Users/stephen/Documents/develop/java-grpc-swagger/src/main/proto/ -I. \
  -I$GOPATH/src \
  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --swagger_out=logtostderr=true:. \
  /Users/stephen/Documents/develop/java-grpc-swagger/src/main/proto/helloworld.proto

對應生成helloworld.swagger.json檔案。在cmd的目錄下新建helloworld.swagger.go,定義常量為Swagger,常量值為helloworld.swagger.json內容

package helloworld

const (
        Swagger = `
        {
          "swagger": "2.0",
          "info": {
            "title": "helloworld.proto",
            "version": "version not set"
          },
          "schemes": [
            "http",
            "https"
          ],
          "consumes": [
            "application/json"
          ],
          "produces": [
            "application/json"
          ],
          "paths": {
            "/v1/hello": {
              "post": {
                "summary": "Sends a greeting",
                "operationId": "SayHello",
                "responses": {
                  "200": {
                    "description": "",
                    "schema": {
                      "$ref": "#/definitions/helloworldHelloReply"
                    }
                  }
                },
                "parameters": [
                  {
                    "name": "body",
                    "in": "body",
                    "required": true,
                    "schema": {
                      "$ref": "#/definitions/helloworldHelloRequest"
                    }
                  }
                ],
                "tags": [
                  "Greeter"
                ]
              }
            }
          },
          "definitions": {
            "helloworldHelloReply": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string"
                }
              },
              "title": "The response message containing the greetings"
            },
            "helloworldHelloRequest": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                }
              },
              "description": "The request message containing the user's name."
            }
          }
        }
        `
)

2.修改proxy.go程式碼

新增方法返回swagger.json的內容

func run() error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()

    mux := http.NewServeMux()
    mux.HandleFunc("/swagger.json", func(w http.ResponseWriter, req *http.Request) {
        io.Copy(w, strings.NewReader(gw.Swagger))
    })

    gwmux := runtime.NewServeMux()
    opts := []grpc.DialOption{grpc.WithInsecure()}
    err := gw.RegisterGreeterHandlerFromEndpoint(ctx, gwmux, *greeterEndpoint, opts)
    if err != nil {
        return err
    }

    log.Print("Greeter gRPC Server gateway start at port 8080...")
    http.ListenAndServe(":8080", mux)
    return nil
}

重新編譯並執行proxy。使用瀏覽器訪問http://localhost:8080/swagger.json,即可得到hello world RESful API的具體說明。

在這裡插入圖片描述 為了將API更直觀顯示出來,我們將swagger-ui安裝到我們的gateway裡面。

3.下載swagger github原始碼

git clone https://github.com/swagger-api/swagger-ui.git

將dist目錄下的所有檔案拷貝到專案目錄resources/swagger-ui裡面

 const ui = SwaggerUIBundle({
        // url: "https://petstore.swagger.io/v2/swagger.json",
        url: "http://localhost:8080/swagger.json",

4.將swagger-ui檔案編譯成go的內建檔案:

1)安裝go-bindata工具
go get -u github.com/jteeuwen/go-bindata/...
2)製作成go的內建資料檔案
go-bindata --nocompress -pkg swagger -o cmd/swagger/ui/data/datafile.go src/main/resources/swagger-ui/...

5.swagger-ui的檔案伺服器

1)elazarl/go-bindata-assetf將內建的資料檔案對外提供http服務
go get github.com/elazarl/go-bindata-assetfs/...
2)修改proxy.go程式碼,新增swagger函式
3)重新編譯proxy.go
go build proxy.go
4)重新啟動gateway服務

使用瀏覽器檢視swagger-ui

http://localhost:8080/swagger-ui

在這裡插入圖片描述

總結

本文至此,已完成grpc服務整合RESTful Json grpc-gateway反向代理和提供swagger-ui介面的配置。