Goのコードからswaggerドキュメントを自動生成する「swag」を紹介

thumnail
2020-07-08

Goのコードからswaggerのドキュメントを自動生成したい

GoでAPIサーバーを開発していてopenapi.ymlに現在生やしているAPIの定義を書かなければいけない場面に遭遇した。実際に手で書いても良いのだが今後、APIを生やすごとに手動で記載するのも結構キツそうなのでコードからopenapi.ymlが生成できれば良いと思い、いろいろ探したところ「swag」というGoのライブラリを発見した。

swagとは

Goアノテーションをswaggerのドキュメントに変換

公式のリポジトリのREADMEには次のように書かれていた。

Swag converts Go annotations to Swagger Documentation 2.0. We've created a variety of plugins for popular Go web frameworks. This allows you to quickly integrate with an existing Go project (using Swagger UI).

参考文献:swaggo/swag https://github.com/swaggo/swag#api-operation

Goアノテーションをswaggerのドキュメントに変換してくれるプラグインだ。Goアノテーションっていうのは後ほども記載するが

// ShowAccount godoc
// @Summary Show a account
// @Description get string by ID
// @ID get-string-by-int
// @Accept  json
// @Produce  json
// @Param id path int true "Account ID"
// @Success 200 {object} model.Account
// @Header 200 {string} Token "qwerty"
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPError
// @Router /accounts/{id} [get]
func (c *Controller) ShowAccount(ctx *gin.Context) {
    id := ctx.Param("id")
    aid, err := strconv.Atoi(id)
    if err != nil {
        httputil.NewError(ctx, http.StatusBadRequest, err)
        return
    }
    account, err := model.AccountOne(aid)
    if err != nil {
        httputil.NewError(ctx, http.StatusNotFound, err)
        return
    }
    ctx.JSON(http.StatusOK, account)
}

こんな感じでメソッドの上などに記載する@を持つコメントのことだ。ちなみに僕はここで思った。「そのまま完全自動でswaggerのドキュメントを生成してくれるのではなく、アノテーションを一度書かないとといけないのか...」つまり、コードを書く時にアノテーションを一緒に書く必要がある。少し面倒だが、他に自動生成ツールもなかったのでこれを使うことに。

swagを実際に使ってみる

echoのAPIサーバーを用意

では早速、swagを使ってみる。今回適当にechoの簡易的なAPIサーバーを用意した。

package main

import (
    "net/http"

    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func main() {
    // Echo instance
    e := echo.New()

    // Middleware
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    // Routes
    e.GET("/", hello)

    // Start server
    e.Logger.Fatal(e.Start(":1323"))
}

// Handler
func hello(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
}

swagのダウンロード方法

次のgo getを叩いてswagをダウンロードする。

go get -u github.com/swaggo/swag/cmd/swag

Goアノテーションを付与する

先ほど用意した簡易的なAPIサーバーに対してGoアノテーションを付与していく。今回は適当に次のように付与してみた。

package main

import (
    "net/http"

    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

// @title Swagger Example API
// @version 1.0
// @description This is a sample swagger server.
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:1323
// @BasePath /
func main() {
    // Echo instance
    e := echo.New()

    // Middleware
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    // Routes
    e.GET("/", hello)

    // Start server
    e.Logger.Fatal(e.Start(":1323"))
}

// @Summary get string
// @Description get "Hello, World!" of string
// @Router / [get]
func hello(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
}

Goアノテーションの付け方は次のREADMEに記載されているので軽く目を通しておくべき。

https://github.com/swaggo/swag#declarative-comments-format

swag iでドキュメントを生成する

Goアノテーションの付与が終わったら、次はドキュメントを自動生成するコマンドを叩く。次のコマンドを叩けば良い。

swag i

そうするとdocsディレクトリの中にdocs.go,swagger.json,swagger.ymlが生成される。

├── docs
│   ├── docs.go
│   ├── swagger.json
│   └── swagger.yaml
└── main.go

swag iには様々なオプションがあるので、用途に応じて使うと良い。

❯ swag i --help
NAME:
   swag init - Create docs.go

USAGE:
   swag init [command options] [arguments...]

OPTIONS:
   --generalInfo value, -g value       Go file path in which 'swagger general API Info' is written (default: "main.go")
   --dir value, -d value               Directory you want to parse (default: "./")
   --exclude value                     exclude directories and files when searching, comma separated
   --propertyStrategy value, -p value  Property Naming Strategy like snakecase,camelcase,pascalcase (default: "camelcase")
   --output value, -o value            Output directory for all the generated files(swagger.json, swagger.yaml and doc.go) (default: "./docs")
   --parseVendor                       Parse go files in 'vendor' folder, disabled by default (default: false)
   --parseDependency                   Parse go files in outside dependency folder, disabled by default (default: false)
   --markdownFiles value, --md value   Parse folder containing markdown files to use as description, disabled by default
   --parseInternal                     Parse go files in internal packages, disabled by default (default: false)
   --generatedTime                     Generate timestamp at the top of docs.go, true by default (default: false)
   --help, -h                          show help (default: false)

swaggerを使ってみる

swaggerを立ち上げる

echoでswaggerを立ち上げるために「echo-swagger」というプラグインを使う。次のコマンドを叩いてダウンロードする。

go get -u github.com/swaggo/echo-swagger

swagger用のAPIを生やす

先ほどのAPIサーバーのコードに次のようにGETの/swagger/*とそれに付随するパッケージを追加する。

package main

import (
    "net/http"

    _ "./docs" // 追加
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
    echoSwagger "github.com/swaggo/echo-swagger" // 追加
)

// @title Swagger Example API
// @version 1.0
// @description This is a sample swagger server.
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:1323
// @BasePath /
func main() {
    // Echo instance
    e := echo.New()

    // Middleware
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    // Routes
    e.GET("/", hello)

    e.GET("/swagger/*", echoSwagger.WrapHandler) // 追加

    // Start server
    e.Logger.Fatal(e.Start(":1323"))
}

// @Summary get string
// @Description get "Hello, World!" of string
// @Router / [get]
func hello(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
}

このように変更した後、go run main.goでAPIサーバーを立ち上げて

http://localhost:1323/swagger/index.html

を叩くとswaggerの画面が現れる。

Screen Shot 2020-07-08 at 8.50.42

これで自由にAPIを叩いたり、APIの仕様などを確認することができる。

KATUBLO

Copyright since 2018 KATUO All Rights Reserved.