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
Swagger
Is 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
Swagger
is 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-gateway
It also supportsSwagger
OpenAPI
Specification
OpenAPI
The 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. OpenAPI
The 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
Swagger
the 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
Swagger
Providing 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 UI
File 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