Skip to content

swag

swaggo/swag は Go 言語における Swagger API 2.0 の実装で、指定フォーマットのコメントを記述するだけで swagger.jsonswagger.yaml 形式のインターフェースドキュメントを生成でき、エクスポートやインポートに便利です。

リポジトリ:swaggo/swag: Automatically generate RESTful API documentation with Swagger 2.0 for Go. (github.com)

ドキュメント:swaggo/swag: Automatically generate RESTful API documentation with Swagger 2.0 for Go. (github.com)

swag がデフォルトでサポートする Web フレームワークは以下の通りです。本文では gin を例として、gin と swagger を組み合わせてインターフェースドキュメントを迅速に生成する例を示します。

TIP

swagger の構文に不慣れな場合は、About Swagger Specification | Documentation | Swagger を参照してください。

インストール

まず swagger コマンドラインツールをダウンロードします。

go install github.com/swaggo/swag/cmd/swag@latest

次に swagger ソースコード依存関係をダウンロードします。

go get github.com/swaggo/swag

TIP

問題が発生しないよう、両者のバージョンは一致させる必要があります。

次に swagger の静的ファイルライブラリ(html、css、js など)をダウンロードします。これらは Go コードに埋め込まれています。

go get github.com/swaggo/files@latest

最後に swagger の gin 適応ライブラリをダウンロードします。

go get github.com/swaggo/gin-swagger@latest

本文では gin のみを例として使用しているため、他の Web フレームワークのアダプターについては自行で調べてください。基本的にほぼ同じです。

使用方法

go mod を使用して最も基本的な Go プロジェクトを作成し、main.go を新規作成して以下の内容を記述します。

go
package main

import (
  "fmt"
  "github.com/gin-gonic/gin"
)

// @title           Swagger Example API
// @version         1.0
// @description     This is a sample server celler server.

// @contact.name   API Support
// @contact.url    http://www.swagger.io/support
// @contact.email  support@swagger.io

// @BasePath  /api/v1
func main() {
  engine := gin.Default()
  engine.GET("/api/v1/ping", Ping)
  engine.Run(":80")
}

// Ping godoc
// @Summary      say hello world
// @Description  return hello world json format content
// @param       name query    string  true  "name"
// @Tags         system
// @Produce      json
// @Router       /ping [get]
func Ping(ctx *gin.Context) {
  ctx.JSON(200, gin.H{
    "message": fmt.Sprintf("Hello World!%s", ctx.Query("name")),
  })
}

これは非常にシンプルな gin Web の例で、main 関数のコメントはドキュメントの基本情報、Ping 関数は通常のインターフェースです。次にコマンドを実行してドキュメントを生成します。デフォルトでは main.go と同じディレクトリの docs ディレクトリに生成されます。

swag init

main.go コードを修正します。

go
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    // 生成されたインターフェースドキュメントパッケージを匿名インポート
    _ "golearn/docs"
)

// @title           Swagger Example API
// @version         1.0
// @description     This is a sample server celler server.

// @contact.name   API Support
// @contact.url    http://www.swagger.io/support
// @contact.email  support@swagger.io

// @BasePath  /api/v1
func main() {
    engine := gin.Default()
    // swagger 静的ファイルルートを登録
    engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    engine.GET("/api/v1/ping", Ping)
    engine.Run(":80")
}

// Ping godoc
// @Summary      say hello world
// @Description  return hello world json format content
// @param       name query    string  true  "name"
// @Tags         system
// @Produce      json
// @Router       /ping [get]
func Ping(ctx *gin.Context) {
    ctx.JSON(200, gin.H{
       "message": fmt.Sprintf("Hello World!%s", ctx.Query("name")),
    })
}

プログラムを実行し、127.0.0.1/swagger/index.html にアクセスすると、インターフェースは以下のようになります。

これで基本的なインターフェースドキュメントが実行されました。次に特に注意すべき点を除けば、基本的に他の言語での使用と大きな違いはありません。

パラメータ

パラメータを定義する形式は以下の通りです。

@param name paramtype datatype isRequired comment

例は以下の通りです。

go
@param userId query int true "user unique id"

サポートされるパラメータタイプは以下の通りです。

  • query
  • path
  • header
  • body
  • formData

データタイプは以下の通りです。

  • string (string)
  • integer (int, uint, uint32, uint64)
  • number (float32)
  • boolean (bool)
  • ユーザー定義構造体

パラメータタイプは独自のタイプにすることもできます。swagger でスキャン可能である必要があります。

レスポンス

インターフェースレスポンスを定義する基本形式は以下の通りです。

go
// @Success      200  {array}   model.Account
// @Failure      400  {object}  httputil.HTTPError
// @Failure      404  {object}  httputil.HTTPError
// @Failure      500  {object}  httputil.HTTPError

ステータスコード、基本タイプ、データタイプで構成されます。{array} は配列であることを示し、データタイプの配列形式で表示されます。{object} はデータタイプの元の形式で表示されます。例えば、通常は統一されたレスポンスボディを定義します。

go
type JSONResult struct {
    Code    int          `json:"code" `
    Message string       `json:"message"`
    Data    interface{}  `json:"data"`
}

Data フィールドのタイプは不確定です。レスポンス例を記述する際に、以下のように組み合わせることができます。

go
// 組み合わせ
@success 200 {object} jsonresult.JSONResult{data=Account} "desc"

// 配列
@success 200 {object} jsonresult.JSONResult{data=[]Account} "desc"

モデル

構造体フィールドにコメントを追加すると、swagger によってモデルフィールドコメントとしてスキャンされます。

go
package model

type Account struct {
  // account id
    ID   int    `json:"id" example:"1"`
    // username
    Name string `json:"name" example:"account name"`
}

example タグの値はページにサンプル値として表示されます。もちろん、フィールド制限もサポートしています。

go
type Foo struct {
    Bar string `minLength:"4" maxLength:"16"`
    Baz int `minimum:"10" maximum:"20" default:"15"`
    Qux []string `enums:"foo,bar,baz"`
}

すべてのモデルは使用時に swagger でスキャン可能であることを確認する必要があります。否则不会起作用。

認証

認証では以下をサポートしています。

  • Basic Auth
  • API Key
  • OAuth2 app auth
  • OAuth2 implicit auth
  • OAuth2 password auth
  • OAuth2 access code auth

インターフェース認証に JWT を使用し、header の Authorization フィールドに保存する場合、以下のように定義できます。

go
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization

本質的にはこれは apikey に過ぎません。bearer token を伝送する場合は、Bearer プレフィックスを手動で追加する必要があります。

次に認証が必要なインターフェースに以下のコメントを追加します。

go
// @security Bearer

この値は securityDefinitions で定義された名前です。

設定

swag は実際には複数の異なる swagger インスタンスを 1 つの map に保存し、ginSwagger はアダプターとしてインスタンスから doc.json(つまり API インターフェース定義ファイル)を読み取り、swaggerFiles は Web ページを表示するための静的 HTML ファイルを提供し、API 定義を解析してインターフェースを生成します。このプロセスを理解した後、カスタム操作を行うことができます。

go
// Name は swag インスタンスを登録するために使用される一意の名前です。
// デフォルトインスタンス名
const Name = "swagger"

var (
  swaggerMu sync.RWMutex
    // インスタンステーブル
  swags     map[string]Swagger
)
go
func CustomWrapHandler(config *Config, handler *webdav.Handler) gin.HandlerFunc {
    var once sync.Once

    if config.InstanceName == "" {
       config.InstanceName = swag.Name
    }

    if config.Title == "" {
       config.Title = "Swagger UI"
    }

    // 名前でテンプレートを作成
    index, _ := template.New("swagger_index.html").Parse(swaggerIndexTpl)

    var matcher = regexp.MustCompile(`(.*)(index\.html|doc\.json|favicon-16x16\.png|favicon-32x32\.png|/oauth2-redirect\.html|swagger-ui\.css|swagger-ui\.css\.map|swagger-ui\.js|swagger-ui\.js\.map|swagger-ui-bundle\.js|swagger-ui-bundle\.js\.map|swagger-ui-standalone-preset\.js|swagger-ui-standalone-preset\.js\.map)[?|.]*`)

    return func(ctx *gin.Context) {
       if ctx.Request.Method != http.MethodGet {
          ctx.AbortWithStatus(http.StatusMethodNotAllowed)

          return
       }

       // ルートマッチング
       matches := matcher.FindStringSubmatch(ctx.Request.RequestURI)

       if len(matches) != 3 {
          ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))

          return
       }

       path := matches[2]
       once.Do(func() {
          handler.Prefix = matches[1]
       })

       switch filepath.Ext(path) {
       case ".html":
          ctx.Header("Content-Type", "text/html; charset=utf-8")
       case ".css":
          ctx.Header("Content-Type", "text/css; charset=utf-8")
       case ".js":
          ctx.Header("Content-Type", "application/javascript")
       case ".png":
          ctx.Header("Content-Type", "image/png")
       case ".json":
          ctx.Header("Content-Type", "application/json; charset=utf-8")
       }

       switch path {
       // メインページ
       case "index.html":
          _ = index.Execute(ctx.Writer, config.toSwaggerConfig())
       // API 記述ファイル
       case "doc.json":
          doc, err := swag.ReadDoc(config.InstanceName)
          if err != nil {
             ctx.AbortWithStatus(http.StatusInternalServerError)

             return
          }

          ctx.String(http.StatusOK, doc)
       default:
          handler.ServeHTTP(ctx.Writer, ctx.Request)
       }
    }
}

生成された Go コードを通じてインスタンス登録を自動的に完了します。以下は自動的に生成された docs.go の一部コードです。

go
// SwaggerInfo はエクスポートされた Swagger Info を保持し、クライアントが変更できるようにします
var SwaggerInfo = &swag.Spec{
  Version:          "",
  Host:             "",
  BasePath:         "",
  Schemes:          []string{},
  Title:            "",
  Description:      "",
  InfoInstanceName: "swagger",
  SwaggerTemplate:  docTemplate,
  LeftDelim:        "{{",
  RightDelim:       "}}",
}

func init() {
    // インスタンスを登録
  swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

init 関数には現在のインスタンスを登録するための Register 関数があることがわかります。インスタンス名を変更したい場合は、このファイルを編集することはお勧めしません。docs.go ファイルは自動的に生成されるため、コード生成時に --instanceName appapi パラメータを使用するだけです。便宜のため、go generate コマンドを使用して Go ファイルに埋め込み、自動コード生成を容易にできます。以下のようにします。

go
// swagger declarative api comment

// @title App Internal API Documentation
// @version v1.0.0
// @description Wilson api documentation
// @BasePath /api/v1
//go:generate swag init --generatedTime --instanceName appapi -g api.go -d ./ --output ./swagger

個人としては swagger の共通情報コメントを main.go または main 関数に記述することは好きではありません。これらのコメントを go generate の上に記述するのが最も適しています。

TIP

複数のインスタンスが必要な場合は、インスタンス名を一意に保つ必要があります。否则 panic します。

設定をカスタマイズするには、ginSwagger.CustomWrapHandler を使用する必要があります。前者より Config パラメータが 1 つ多く、意味は以下の通りです。

go
// Config は ginSwagger 設定変数を保存します。
type Config struct {
  // API 定義を指す URL(通常は swagger.json または swagger.yaml)。デフォルトは `doc.json`。
  URL                      string
    // インターフェースリスト展開状態
  DocExpansion             string
    // インスタンス名
  InstanceName             string
    // タイトル
  Title                    string
    // 展開深度
  DefaultModelsExpandDepth int
    // 名前の通り
  DeepLinking              bool
  PersistAuthorization     bool
  Oauth2DefaultClientID    string
}

swaggerFiles.NewHandler() を使用してデフォルトの Handler を置き換えます。複数のインスタンスの場合は特に如此です。

go
engine.GET(openapi.ApiDoc, ginSwagger.CustomWrapHandler(openapi.Config, swaggerFiles.NewHandler()))

これに加えて、タイプ書き換えなどの一連の操作も可能です。これらはすべて比較的簡単です。詳細は公式ドキュメントを参照してください。

注意事項

  1. swag はコメントに基づいて openapi のインターフェース記述ファイルを生成します。生成時、指定されたディレクトリにはインターフェースドキュメントの基本情報を含める必要があります。デフォルトでは main.go で検索されます。

  2. swag init はデフォルトで現在のディレクトリを指定し、値は ./ です。swag init -d を使用して複数のディレクトリを指定できます。カンマで区切り、最初に指定されたディレクトリにはインターフェースドキュメントの基本情報を含める必要があります。例えば

    swag init -d ./,./api
  3. -g、インターフェースドキュメントの基本情報の保存ファイルはカスタムファイル名にできます。デフォルトは main.go です。ドキュメント生成時に -g パラメータを使用してファイル名を指定します。

    swag init -g api.go -d ./,./api

    このコマンドの意味は、./api.go でインターフェースドキュメントの基本情報を解析し、同時に ././api の 2 つのディレクトリで他のインターフェースのコメント情報を検索・解析して対応するドキュメントを生成することです。

  4. -o パラメータはドキュメント記述ファイルの出力パスを指定できます。デフォルトは ./docs です。例:

    swag init -o ./api/docs
  5. --ot は出力ファイルタイプを指定できます。デフォルトは(docs.go,swagger.json,swagger.yaml)です。swagger ui を Go プログラムで読み込む場合は、go ファイルが不可欠です。

    swag init --ot go,yaml

    その他生成された json と yaml ファイルは、他のインターフェース管理ソフトウェアでデータをインポートするのに便利です。

  6. コメントをどこに記述しても同じです。関数上に記述しなくても解析できます。関数上に記述するのは可読性が良いだけです。本質的にはコメント形式と Go ソースコードが一緒に埋め込まれた DSL です。

  7. swag は多くの他のパラメータもサポートしています。swag init -h を使用して確認できます。

Golang学习网由www.golangdev.cn整理维护