Skip to content

swag

swaggo/swag adalah implementasi Swagger API 2.0 dalam bahasa Go dengan menulis komentar format tertentu dapat menghasilkan file dokumentasi interface swagger.json dan swagger.yaml mudah untuk export dan import.

Repositori: swaggo/swag: Automatically generate RESTful API documentation with Swagger 2.0 for Go. (github.com)

Dokumentasi: swaggo/swag: Automatically generate RESTful API documentation with Swagger 2.0 for Go. (github.com)

swag mendukung framework web default sebagai berikut artikel ini menggunakan gin sebagai contoh untuk mendemonstrasikan contoh menghasilkan dokumentasi interface dengan cepat menggunakan gin dan swagger.

TIP

Jika tidak familiar dengan sintaks swagger dapat pergi ke About Swagger Specification | Documentation | Swagger

Instalasi

Pertama download tool command line swagger

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

Kemudian download dependensi source code swagger

go get github.com/swaggo/swag

TIP

Untuk menghindari masalah versi keduanya harus konsisten.

Kemudian download library file statis swagger html css js dan lain-lain semuanya tertanam dalam kode Go.

go get github.com/swaggo/files@latest

Terakhir download library adaptasi gin swagger

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

Karena artikel ini hanya menggunakan gin sebagai contoh adaptor framework web lainnya dapat dipelajari sendiri pada dasarnya hampir sama.

Penggunaan

Gunakan go mod untuk membuat proyek Go paling dasar buat main.go tulis konten berikut.

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")),
  })
}

Ini adalah contoh gin web yang sangat sederhana komentar pada fungsi main adalah informasi dasar dokumentasi fungsi Ping adalah interface biasa. Selanjutnya jalankan command untuk menghasilkan dokumentasi default berada di direktori docs yang setara dengan main.go

swag init

Modifikasi kode main.go

go
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    // anonymous import paket dokumentasi interface yang dihasilkan
    _ "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()
    // mendaftarkan route statis 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")),
    })
}

Jalankan program akses 127.0.0.1/swagger/index.html interface sebagai berikut

Dengan demikian telah menjalankan dokumentasi interface dasar. Selanjutnya kecuali beberapa poin yang perlu diperhatikan pada dasarnya tidak ada perbedaan besar dengan bahasa lain.

Parameter

Format definisi parameter adalah

@param name paramtype datatype isRequired comment

Satu contoh sebagai berikut

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

Di antara jenis parameter yang didukung adalah

  • query
  • path
  • header
  • body
  • formData

Jenis data adalah

  • string (string)
  • integer (int, uint, uint32, uint64)
  • number (float32)
  • boolean (bool)
  • user defined struct

Jenis parameter juga dapat menjadi jenis Anda sendiri asalkan dapat dipindai oleh swagger.

Response

Format dasar definisi response interface adalah sebagai berikut

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

Terdiri dari status code jenis dasar jenis data. {array} menunjukkan adalah array akan menampilkan bentuk array jenis data {object} akan menampilkan bentuk asli jenis data. Misalnya biasanya kita akan mendefinisikan response body terpadu

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

Jenis field Data tidak pasti saat mendeskripsikan use case response dapat dikombinasikan sebagai berikut

go
// Kombinasi
@success 200 {object} jsonresult.JSONResult{data=Account} "desc"

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

Model

Menambahkan komentar field struct akan dipindai oleh swagger sebagai field komentar model

go
package model

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

Di antara nilai tag example akan ditampilkan sebagai nilai contoh di halaman tentu saja juga mendukung batasan field

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

Semua model saat digunakan harus memastikan dapat dipindai oleh swagger jika tidak tidak akan berfungsi.

Autentikasi

Dalam hal autentikasi mendukung

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

Jika autentikasi interface menggunakan JWT disimpan di field Authorization di header kita dapat mendefinisikan sebagai berikut

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

Pada dasarnya ini hanya apikey jika Anda mengirimkan bearer token perlu menambahkan prefix Bearer secara manual.

Kemudian di interface yang memerlukan autentikasi tambahkan komentar berikut

go
// @security Bearer

Nilainya adalah nama definisi securityDefinitions Anda.

Konfigurasi

swag sebenarnya menyimpan beberapa instance swagger berbeda dalam map ginSwagger sebagai adaptor membaca doc.json dari instance yaitu file definisi interface API swaggerFiles menyediakan file HTML statis untuk menampilkan halaman web mengurai definisi API dan menghasilkan interface setelah memahami seluruh proses dapat melakukan operasi kustom.

go
// Name is a unique name be used to register swag instance.
// nama instance default
const Name = "swagger"

var (
  swaggerMu sync.RWMutex
    // tabel instance
  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"
    }

    // membuat template dengan nama
    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
       }

       // pencocokan route
       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 {
       // halaman utama
       case "index.html":
          _ = index.Execute(ctx.Writer, config.toSwaggerConfig())
       // file deskripsi 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)
       }
    }
}

Melalui kode Go yang dihasilkan secara otomatis menyelesaikan registrasi instance di bawah adalah sebagian kode docs.go yang dihasilkan secara otomatis

go
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
  Version:          "",
  Host:             "",
  BasePath:         "",
  Schemes:          []string{},
  Title:            "",
  Description:      "",
  InfoInstanceName: "swagger",
  SwaggerTemplate:  docTemplate,
  LeftDelim:        "{{",
  RightDelim:       "}}",
}

func init() {
    // registrasi instance
  swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

Dapat dilihat ada fungsi Register di fungsi init yang digunakan untuk registrasi instance saat ini jika ingin mengubah nama instance tidak disarankan untuk mengedit di file ini karena file docs.go dihasilkan secara otomatis hanya perlu menggunakan parameter --instanceName appapi saat menghasilkan kode. Untuk kenyamanan dapat menggunakan command go generate yang tertanam dalam file Go untuk memudahkan menghasilkan kode secara otomatis sebagai berikut.

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

Secara pribadi tidak suka menulis komentar umum swagger di main.go atau fungsi main menulis komentar ini di atas go generate paling tepat.

TIP

Jika memerlukan beberapa instance pastikan nama instance unik jika tidak akan panic

Untuk mengustomisasi beberapa konfigurasi perlu menggunakan ginSwagger.CustomWrapHandler dibandingkan yang sebelumnya memiliki parameter Config tambahan penjelasannya sebagai berikut

go
// Config stores ginSwagger configuration variables.
type Config struct {
  // url yang menunjuk ke definisi API (biasanya swagger.json atau swagger.yaml). Default adalah `doc.json`.
  URL                      string
    // status expand daftar interface
  DocExpansion             string
    // nama instance
  InstanceName             string
    // judul
  Title                    string
    // kedalaman expand
  DefaultModelsExpandDepth int
    // sesuai namanya
  DeepLinking              bool
  PersistAuthorization     bool
  Oauth2DefaultClientID    string
}

Gunakan swaggerFiles.NewHandler() untuk menggantikan Handler default terutama saat menggunakan beberapa instance.

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

Selain itu juga dapat melakukan operasi seperti rewrite jenis dan lain-lain semuanya cukup sederhana konten lebih lanjut dapat membaca dokumentasi resmi.

Perhatian

  1. swag menghasilkan file deskripsi interface openapi berdasarkan komentar saat menghasilkan direktori yang ditentukan harus berisi informasi dasar dokumentasi interface default dicari di main.go

  2. swag init default menentukan direktori saat ini nilainya ./ dapat menggunakan swag init -d untuk menentukan beberapa direktori gunakan koma untuk memisahkan direktori yang ditentukan pertama harus berisi informasi dasar dokumentasi interface. Misalnya

    swag init -d ./,./api
  3. -g nama file tempat informasi dasar dokumentasi interface disimpan dapat dikustomisasi default adalah main.go saat menghasilkan dokumentasi gunakan parameter -g untuk menentukan nama file

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

    Command ini berarti mengurai informasi dasar dokumentasi interface di ./api.go sekaligus mencari dan mengurai informasi komentar interface lain di direktori ./ dan ./api dan menghasilkan dokumentasi yang sesuai.

  4. Parameter -o dapat menentukan path output file deskripsi dokumentasi default adalah ./docs contoh:

    swag init -o ./api/docs
  5. --ot dapat menentukan jenis file output default adalah (docs.go,swagger.json,swagger.yaml) jika ingin menggunakan program Go untuk memuat swagger ui file Go sangat diperlukan.

    swag init --ot go,yaml

    File json dan yaml yang dihasilkan sisanya dapat dengan mudah mengimpor data di software manajemen interface lainnya.

  6. Menulis komentar di mana saja sama bahkan jika tidak ditulis di fungsi juga dapat diurai hanya saja menulis di fungsi lebih baik readability pada dasarnya masih DSL yang tertanam dalam bentuk komentar dan source code Go.

  7. swag juga mendukung banyak parameter lainnya dapat menggunakan swag init -h untuk melihat.

Golang by www.golangdev.cn edit