阅读时间:5min左右
本文目的:
说明如何使用grpc-gateway(下图红色部分)反向代理插件将RESTful JSON API转换为gRPC,并使用swagger ui提供rest api界面。
集成步骤:
上图所示,由下往上
一、HelloWorld gRPC服务
首先先有一个gRPC服务,我们这个服务使用java实现,并使用maven进行管理,具体细节可查看git库:
1.安装所需软件版本
安装包 | 版本 | 备注 |
---|---|---|
go | 1.13.1 | (必须,安装包链接:https://golang.org/dl/) |
protobuf | 3.6.1 | (必须,https://github.com/protocolbuffers/protobuf/releases) |
java | 1.8.0 | (可选,原因是grpc服务是由java编写) |
maven | 3.5.4 | (可选) |
安装步骤不再展开,我相信你们可以安装好的。
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里面
修改swagger-ui/index.html,替换
“http://petstore.swagger.io/v2/swagger.json”
为"http://localhost:8080/swagger.json"
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界面的配置。
参考
https://github.com/grpc-ecosystem/grpc-gateway
https://coreos.com/blog/grpc-protobufs-swagger.html
https://github.com/swagger-api/swagger-ui/tree/8062a9eca0dc9d037d2c4940c0a592b15b61bd21
https://www.cnblogs.com/lienhua34/p/6285829.html