golang:echoでSwagger UIを使ってみる
echoで同じポートでSwagger UIを開けるようにするのに少し詰まった為メモ
sampleはgithub参照
今回使ったもの
ディレクトリ構成
echo-swagger/ ├ main.go ├ hello/ │ └ controller/ │ └ hello_controller.go ├ swagger-ui/ │ ├ swagger-ui.go │ ├ docs.go │ ├ index.html │ ├ o2c.html │ ├ swagger-ui.js │ ├ swagger-ui.min.js │ ├ css/ │ ├ lib/ │ └ images/ └ vendor/
実際に書いたコード
main.go
// @APIVersion 1.0.0 // @APITitle echo-swagger // @APIDescription echo-swagger sample api // @BasePath http://localhost:8080/swagger-ui // @SubApi hello [/hello] package main import ( helloC "github.com/go-examples/echo-swagger/hello/controller" swaggerui "github.com/go-examples/echo-swagger/swagger-ui" "github.com/labstack/echo" ) func main() { e := echo.New() helloC.NewHelloController(e) swaggerui.NewSwaggerController(e) e.Logger.Fatal(e.Start(":8080")) }
まずはmain.go ポイントはBasePathを{host}:{port}/swagger-uiにしたところ ここを{host}:{port}にするとswagger for Goで生成するファイルのAPI定義を読み込んでくれなくなる
hello_contoller.go
package controller import ( "net/http" "github.com/labstack/echo" ) // HelloController hello controller type HelloController struct{} // NewHelloController mount hello controller func NewHelloController(e *echo.Echo) { handler := &HelloController{} e.GET("/hello", handler.Hello) } // Hello hello world // @Title Hello // @Description Hello 'your name' // @Assept json // @Param name query string true "名前" // @Success 200 {object} string true "Hello 'your name'" // @Resource /hello // @Router /hello [get] func (c *HelloController) Hello(ctx echo.Context) error { name := ctx.QueryParam("name") return ctx.String(http.StatusOK, "Hello, "+name) }
controllerに関してはドキュメントどおりに作成
swagger-ui.go
package swaggerui import ( "flag" "html/template" "net/http" "strings" "github.com/labstack/echo" ) var apiurl = flag.String("api", "http://localhost", "The base path URI of the API service") // SwaggerController swagger controller type SwaggerController struct{} // NewSwaggerController mount swagger controller func NewSwaggerController(e *echo.Echo) { handler := &SwaggerController{} flag.Parse() e.GET("/", echo.WrapHandler(http.HandlerFunc(handler.IndexHandler))) e.Static("/swagger-ui", "./swagger-ui/") for apiKey := range apiDescriptionsJson { e.GET("/swagger-ui/"+apiKey, echo.WrapHandler(http.HandlerFunc(handler.APIDescriptionHandler))) } } // IndexHandler index handler func (c *SwaggerController) IndexHandler(w http.ResponseWriter, r *http.Request) { isJSONRequest := false if acceptHeaders, ok := r.Header["Accept"]; ok { for _, acceptHeader := range acceptHeaders { if strings.Contains(acceptHeader, "json") { isJSONRequest = true break } } } if isJSONRequest { w.Write([]byte(resourceListingJson)) } else { http.Redirect(w, r, "/swagger-ui/", http.StatusFound) } } // APIDescriptionHandler api description handler func (c *SwaggerController) APIDescriptionHandler(w http.ResponseWriter, r *http.Request) { apiKey := strings.Split(strings.Trim(r.RequestURI, "/"), "/") if json, ok := apiDescriptionsJson[apiKey[1]]; ok { t, e := template.New("desc").Parse(json) if e != nil { w.WriteHeader(http.StatusInternalServerError) return } t.Execute(w, *apiurl) } else { w.WriteHeader(http.StatusNotFound) } }
swagger-uiのcontrollerはswagger for goのweb.go-exampleの中身を書き換えたものを作成
IndexHandlerとAPIDescriptionHandlerはそのまま使用し、
Routingの際にecho.WrapHandlerでラップする
e.Static("/swagger-ui", "./swagger-ui/")
ここの部分はweb.go-exampleでは下記のようになっているがecho.staticで/swagger
で静的ファイルを読み込むように変更
http.Handle("/swagger-ui/", http.StripPrefix("/swagger-ui/", http.FileServer(http.Dir(*staticContent))))
Makefile
REPO=github.com/go-examples/echo-swagger ## generate swagger gen-swagger: # swaggerファイル生成 swagger -apiPackage="$(REPO)" -mainApiFile="$(REPO)/main.go" -output=./swagger-ui sed -i -e "s/package main/package swaggerui/g" ./swagger-ui/docs.go sed -i -e "s/\"basePath\": \"http:\/\/localhost:8080\/swagger-ui\"/\"basePath\": \"http:\/\/localhost:8080\"/g" swagger-ui/docs.go sed -i -e "1,/\"basePath\": \"http:\/\/localhost:8080\"/s/\"basePath\": \"http:\/\/localhost:8080\"/\"basePath\": \"http:\/\/localhost:8080\/swagger-ui\"/" swagger-ui/docs.go
ポイントはAPP定義のbasePathは{host}/swagger
に設定
各APIのbasePathは{host}/
に設定すること
こうすることでSwagger UIから実際にAPIを叩くことができるようになる
更に、package名をswaggeruiにすることで変数をswagger-ui.goで使用できるようにする
起動してみる
$ make gen-swagger $ go build $ ./echo-swagger
http://localhost:8080
にアクセスして確認
無事Swagger UIを表示させることが出来た