【swaggo】GoのGoDocからSwaggerを書き出そう(基本編)
swaggo
今回紹介するswaggoはyvasiyarov/swaggerにインスパイアを受けて、作成したOSSになります。現在、yvasiyarov/swaggerは開発が止まっているので、いくつかの問題が放置されたままになっています。(これはOSSなので仕方ないです) swaggoは元の構文をそのまま流用して、機能追加をしているものになります。
- Swagger 2.0の対応
- 複雑な構造体の解析
- カスタムヘッダー
- example value
- セキュリティ
私がざっと見た限り、上の内容はswaggoで無ければ使えないっぽいです。
Swagger便利だけど、書くのがそもそもだるい
最近になって、よくSwaggerというワードを目にするようになりました。これはとても画期的で、APIに実際にリクエストを投げれるドキュメントが出来上がります。 しかし、このドキュメントのコードを書くのが結構面倒!
もし、既に実装されているコードからSwaggerを生み出すことが出来るものがあったら、最高ですよね?ということで、今回はswaggoを使ったドキュメント生成を紹介します。
実装方法
だらだら書いても仕方ないので、さくっとコード例を書きます。 今回の記事に使ったコードはこちらにあります。 また、今回、紹介する内容は、公式ドキュメントに詳しく記載があります。
General API Info
Swaggerの基本情報をmain.go(オプションで変えることも出来ます)に書きます。 設定出来る項目
package main import ( "github.com/gin-gonic/gin" "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" "github.com/swaggo/swag/example/celler/controller" _ "github.com/swaggo/swag/example/celler/docs" ) // @title Swagger Example API // @version 1.0 // @description This is a sample server celler server. // @termsOfService http://swagger.io/terms/ // @contact.name API Support // @contact.url http://www.swagger.io/support // @contact.email support@swagger.io // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html // @host localhost:8080 // @BasePath /api/v1 // @securityDefinitions.basic BasicAuth // @securityDefinitions.apikey ApiKeyAuth // @in header // @name Authorization // @securitydefinitions.oauth2.application OAuth2Application // @tokenUrl https://example.com/oauth/token // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information // @securitydefinitions.oauth2.implicit OAuth2Implicit // @authorizationurl https://example.com/oauth/authorize // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information // @securitydefinitions.oauth2.password OAuth2Password // @tokenUrl https://example.com/oauth/token // @scope.read Grants read access // @scope.write Grants write access // @scope.admin Grants read and write access to administrative information // @securitydefinitions.oauth2.accessCode OAuth2AccessCode // @tokenUrl https://example.com/oauth/token // @authorizationurl https://example.com/oauth/authorize // @scope.admin Grants read and write access to administrative information func main() { r := gin.Default() c := controller.NewController() v1 := r.Group("/api/v1") { accounts := v1.Group("/accounts") { accounts.GET(":id", c.ShowAccount) accounts.GET("", c.ListAccounts) accounts.POST("", c.AddAccount) accounts.DELETE(":id", c.DeleteAccount) accounts.PATCH(":id", c.UpdateAccount) accounts.POST(":id/images", c.UploadAccountImage) } /... } r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) r.Run(":8080") }
API Operation
エンドポイントに関する情報書きます。 設定出来る項目 よく使う項目をピックアップして説明致します。
package controller //... // ShowAccount godoc // @Summary Show a account // @Description get string by ID // @Accept json // @Produce json // @Param id path int true "Account ID" // @Success 200 {object} model.Account // @Failure 400 {object} controller.HTTPError // @Failure 404 {object} controller.HTTPError // @Failure 500 {object} controller.HTTPError // @Router /accounts/{id} [get] func (c *Controller) ShowAccount(ctx *gin.Context) { id := ctx.Param("id") aid, err := strconv.Atoi(id) if err != nil { NewError(ctx, http.StatusBadRequest, err) return } account, err := model.AccountOne(aid) if err != nil { NewError(ctx, http.StatusNotFound, err) return } ctx.JSON(http.StatusOK, account) }
エンドポイントの説明
// @Summary Show a account` // @Description get string by ID`
MimeType
// @Accept json // @Produce json
APIが許可しているMimeTypeを設定できます。 設定出来るMimeType
Param
// @Param パラメーター名 種類 型 必須要素か? コメント
// @Param id path int true "Account ID" // @Param q query string false "name search by q" // @Param account body model.AddAccount true "Add account" // @Param Authorization header string true "Authentication header"
- path: パスパラメーター
- query: クエリパラメータ
- body: そのまんまです
- header: カスタムリクエストヘッダー
パラメーターの型として、string, int, fileなどが利用が出来ます。
Result
// @Success ステータスコード パラメーターの型 データの型 コメント
// @Success 200 {object} model.Account // @Failure 400 {object} controller.HTTPError // @Failure 404 {object} controller.HTTPError // @Failure 500 {object} controller.HTTPError
成功のパターンと失敗のパターンを必要分だけ用意します。
構造体の指定の仕方
// @Success 200 {object} model.Account
上記のように書くと、package名.構造体名
のような感じで探しに行って、ヒモ付を行なってくれます。
package model // ... type Account struct { ID int `json:"id" example:"1"` Name string `json:"name" example:"account name"` }
example
に設定された値は、Swaggerで出した時の具体例として設定されます。
json
に設定された値は、JSONのキー名を決定します。
つまり、上記の例の場合、{"id": 1, "name": "account name"}
というJSONが出来上がります。
Security
// @Security ApiKeyAuth
General API Infoで定義したセキュリティを使うことが出来ます。これの使い方については、別の記事で詳しく取り上げる予定です。
Authentication - Swagger
Router
// @Router /accounts/{id} [get]
エンドポイントのURIとメソッドを指定します。このURIはGeneral API infoでのBasePathからの相対パスを設定する必要があります。
// @BasePath /api/v1
今回の場合だと、最終的に出来上がるエンドポイントは、/api/v1/accounts/{id}となります。
Swaggerコード生成
$ go get -u github.com/swaggo/swag/cmd/swag $ swag init
上記をmain.goのあるパスで実行すると、docsフォルダが出来上がります。そこに、swaggerドキュメントに関するコードが生成されます。
. ├── README.md ├── controller ├── docs <-- これが自動生成される │ ├── docs.go │ └── swagger │ ├── swagger.json │ └── swagger.yaml ├── main.go └── model
i -h 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: "./") --swagger value, -s value Output the swagger conf for json and yaml (default: "./docs/swagger")
ちなみに、このinitコマンドには、上記のようなオプションがあるので、自分の環境に合わせて変更が可能です。
//... "/accounts/{id}": { "get": { "description": "get string by ID", "consumes": [ "application/json" ], "produces": [ "application/json" ], "summary": "Show a account", "operationId": "get-string-by-int", "parameters": [ { "type": "integer", "description": "Account ID", "name": "id", "in": "path", "required": true } ], "responses": { "200": { "schema": { "type": "object", "$ref": "#/definitions/model.Account" } }, "400": { "schema": { "type": "object", "$ref": "#/definitions/controller.HTTPError" } }, "404": { "schema": { "type": "object", "$ref": "#/definitions/controller.HTTPError" } }, "500": { "schema": { "type": "object", "$ref": "#/definitions/controller.HTTPError" } } } }, //...
実際にSwaggerからリクエストを投げてみよう
swaggerのコードを読み込んで、使うのも良いですが、今回はswaggoが用意している便利な関数を使って、UIを呼び出したいと思います。ちなみに、そのコードは既に例に含まれています。
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
http://localhost:8080/swagger/index.htmlには既にSwaggerUIが展開されており、リクエストが出来る状態になっています。 このハンドラは、gin Echo net/httpをサポートしています。対応していないものを使っている場合は、自分でSwaggerUIを用意する必要があります。(PR投げれば種類を増やせます!)
まとめ
現状、簡単なAPIなら十分ドキュメント生成に活用出来ます。是非使ってみてください。 あと、自分が関わっているOSSということもあり、意見募集中です!w