This is a creation in Article, where the information may have evolved or changed.
Swagger, look.
In the previous section, we completed a service-side support at the same time Rpc and RESTful Api after you thought you were done, the results suddenly found to write Api documents and front-end colleague Docking = = ...
You're wondering if there are any components that can automate the generation of Api documents to solve this problem, and then you find out Swagger and get to know them together!
Introduced
Swagger
SwaggerIs the world's largest OpenAPI normative (OAS) API development tool framework that supports the development of the entire API lifecycle from design and documentation to testing and deployment
Swaggeris currently one of the most popular RESTful Api document generation tools, mainly for the following reasons
- Cross-platform, cross-language support
- A strong community
- Eco-Circle Swagger Tools (Swagger Editor, Swagger Codegen, Swagger UI ... )
- Powerful console
grpc-gatewayIt also supportsSwagger
OpenAPISpecification
OpenAPIThe specification is Linux a project of the foundation that attempts to standardize the RESTful service development process by defining a language that describes the API format or API definition. OpenAPIThe specification helps us to describe the basic information of an API, such as:
- General description of the API
- Available paths (/Resources)
- Available actions on each path (get/submit ...) )
- Input/output format for each operation
Currently the V2.0 version of the OPENAPI specification (i.e. the SWAGGERV2.0 specification) has been released and open source on GitHub. The document is very well written and has a clear structure for easy access at any time.
Note: OpenAPI the introduction of the specification is quoted from the original
Use
Swaggerthe generated description file
first , we need to check whether the protoc-gen-swagger executable file is included under $gobin
If it does not exist, it needs to be executed:
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
After the execution has been completed, you can $GOPATH/bin find the execution file below and move it to the $GOBIN next
second , go back $GOPATH/src/grpc-hello-world/proto and execute the order.
protoc -I/usr/local/include -I. -I$GOPATH/src/grpc-hello-world/proto/google/api --swagger_out=logtostderr=true:. ./hello.proto
After successful execution ls you can see the hello.swagger.json file
Download Swagger UI file
SwaggerProviding a visual API management platform is the swagger UI
We download its source code and dist copy all the files in its directory to our project. $GOPATH/src/grpc-hello-world/third_party/swagger-ui
will be Swagger UI converted to Go source code
The conversion tool we use here is Go-bindata
It supports the conversion of any file to manageable Go source code. Used to embed binary data into the Go program. And you can choose to compress the file data before converting the file data to the original byte slice
Installation
go get -u github.com/jteeuwen/go-bindata/...
When you are finished, $GOPATH/bin go-bindata Move down to the $GOBIN bottom
Transformation
Create a new directory under the project pkg/ui/data/swagger , go back $GOPATH/src/grpc-hello-world/third_party/swagger-ui , execute the command
go-bindata --nocompress -pkg swagger -o pkg/ui/data/swagger/datafile.go third_party/swagger-ui/...
Check
Go back to pkg/ui/data/swagger the table of contents to check if datafile.go files exist
Swagger UIFile server (external service)
In this step, we need to use the matching Go-bindata-assetfs
It can use the go-bindata generated Swagger UI Go code, combined with net/http external services
Installation
go get github.com/elazarl/go-bindata-assetfs/...
Write
Through analysis, we learned that the generated file provides a assetFS function that returns an embedded file that is encapsulated http.Filesystem and can be used to provide a HTTP service
So let's write Swagger UI the code, mostly two parts, one is swagger.json , the other is swagger-ui the response
Serveswaggerfile
Reference Packages strings ,path
func serveSwaggerFile(w http.ResponseWriter, r *http.Request) { if ! strings.HasSuffix(r.URL.Path, "swagger.json") { log.Printf("Not Found: %s", r.URL.Path) http.NotFound(w, r) return } p := strings.TrimPrefix(r.URL.Path, "/swagger/") p = path.Join("proto", p) log.Printf("Serving swagger-file: %s", p) http.ServeFile(w, r, p)}
In the function, we use r.URL.Path the path suffix to judge
Main swagger.json file access support (provided https://127.0.0.1:50052/swagger/hello.swagger.json access)
Serveswaggerui
Reference Packages github.com/elazarl/go-bindata-assetfs ,grpc-hello-world/pkg/ui/data/swagger
func serveSwaggerUI(mux *http.ServeMux) { fileServer := http.FileServer(&assetfs.AssetFS{ Asset: swagger.Asset, AssetDir: swagger.AssetDir, Prefix: "third_party/swagger-ui", }) prefix := "/swagger-ui/" mux.Handle(prefix, http.StripPrefix(prefix, fileServer))}
In the function, we use the Go-bindata-assetfs to dispatch the previously generated datafile.go service, which is combined net/http to provide swagger-ui services externally.
Combine
After we have finished the function, we find that it path.Join("proto", p) is written to the dead parameter, so obviously it is wrong, we should export it as an external parameter, then we will finally retrofit
First we are server.go adding global variables to the package SwaggerDir , modifying the cmd/server.go file:
Package Cmdimport ("Log" "Github.com/spf13/cobra" "Grpc-hello-world/server") var servercmd = &cobra. command{use: "Server", Short: "Run the Grpc hello-world server", Run:func (cmd *cobra. Command, args []string] {defer func () {if err: = Recover (); Err! = nil {log. PRINTLN ("Recover Error:%v", Err)}} () server. Run ()},}func init () {servercmd.flags (). Stringvarp (&server. ServerPort, "Port", "P", "50052", "Server Port") servercmd.flags (). Stringvarp (&server. Certpempath, "Cert-pem", "", "./conf/certs/server.pem", "Cert-pem Path") servercmd.flags (). Stringvarp (&server. Certkeypath, "Cert-key", "", "./conf/certs/server.key", "Cert-key Path") servercmd.flags (). Stringvarp (&server. Certservername, "Cert-server-name", "", "GRPC server name", "Server ' hostname") servercmd.flags (). Stringvarp (&server. Swaggerdir, "Swagger-dir", "", "Proto", "Path to the directory which COntains swagger Definitions ") Rootcmd.addcommand (Servercmd)}
Modified path.Join("proto", p) to path.Join(SwaggerDir, p) , so that our swagger.json file path can be modified according to external conditions
Final server.go file content:
Package Serverimport ("Crypto/tls" "Net" "Net/http" "Log" "Strings" "Path" Golang.org/x/net/context "" Google.golang.org/grpc "" Google.golang.org/grpc/credentials "" Github.com/grpc-ecosystem/grpc-gateway/runtime " "Github.com/elazarl/go-bindata-assetfs" PB "Grpc-hello-world/proto" "Grpc-hello-world/pkg/util" "Grpc-hell O-world/pkg/ui/data/swagger ") var (serverport string Certservername string Certpempath string Certkeypath stri Ng Swaggerdir string EndPoint string Tlsconfig *tls. Config) Func Run (err error) {EndPoint = ":" + serverport tlsconfig = util. Gettlsconfig (Certpempath, Certkeypath) conn, err: = Net. Listen ("TCP", EndPoint) if err! = Nil {log. Printf ("TCP Listen err:%v\n", Err)} SRV: = NewServer (conn) log. Printf ("Grpc and HTTPS listen on:%s\n", serverport) if Err = srv. Serve (util. Newtlslistener (conn, tlsconfig)); Err! = Nil {log. Printf ("Listenandserve:%v\n", err)}Return err} func newserver (conn net. Listener) (*http. Server) {grpcserver: = Newgrpc () Gwmux, err: = Newgateway () if err! = Nil {panic (err)} MUX: = Htt P.newservemux () Mux. Handle ("/", Gwmux) mux. Handlefunc ("/swagger/", Serveswaggerfile) Serveswaggerui (MUX) return &http. server{Addr:endpoint, Handler:util. Grpchandlerfunc (Grpcserver, MUX), Tlsconfig:tlsconfig,}}func newgrpc () *grpc. Server {creds, err: = credentials. Newservertlsfromfile (Certpempath, Certkeypath) if err! = Nil {panic (err)} opts: = []grpc. serveroption{Grpc. Creds (creds),} server: = Grpc. NewServer (opts ...) Pb. Registerhelloworldserver (server, Newhelloservice ()) return Server}func Newgateway () (HTTP. Handler, error) {CTX: = context. Background () dcreds, err: = credentials. Newclienttlsfromfile (Certpempath, certservername) if err! = Nil {return nil, err} dopts: = []grpc. Dialoption{grpc. WithtrAnsportcredentials (Dcreds)} Gwmux: = Runtime. Newservemux () If err: = PB. Registerhelloworldhandlerfromendpoint (CTX, Gwmux, EndPoint, dopts); Err! = Nil {return nil, err} return Gwmux, Nil}func serveswaggerfile (w http. Responsewriter, R *http. Request) {if! strings. Hassuffix (R.url. Path, "Swagger.json") {log. Printf ("Not Found:%s", R.url. Path) http. NotFound (W, R) return} P: = Strings. Trimprefix (R.url. Path, "/swagger/") p = path. Join (Swaggerdir, p) log. Printf ("Serving Swagger-file:%s", p) http. Servefile (W, R, p)}func Serveswaggerui (Mux *http. Servemux) {fileserver: = http. Fileserver (&assetfs. assetfs{Asset:swagger. Asset, Assetdir:swagger. Assetdir, Prefix: "Third_party/swagger-ui",}) Prefix: = "/swagger-ui/" MUX. Handle (prefix, http. Stripprefix (prefix, fileserver))}
Test
Access the path to https://127.0.0.1:50052/swagger/hello.swagger.json see if the output is content hello.swagger.json , for example:
Access path https://127.0.0.1:50052/swagger-ui/ , view content
Summary
This chapter is now complete, Swagger and its ecological circle is very rich, interested in the study of small partners can go to their official website to seriously study
And the current level of completion to meet the needs of the daily work, can be more automated RESTful Api document generation, complete and interface docking
Reference
Sample code