Skip to content

swag

swaggo/swag Swagger API 2.0'ın Go dilindeki bir implementasyonudur. Belirli bir formatta yorum yazarak swagger.json ve swagger.yaml türünde API dokümantasyonu oluşturabilir. Dışa ve içe aktarma için uygundur.

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

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

swag varsayılan olarak aşağıdaki web framework'lerini destekler. Bu makalede gin örneği kullanılarak gin ile swagger'ın nasıl hızlı bir şekilde API dokümantasyonu oluşturacağı gösterilecektir.

TIP

Swagger syntax'ine aşina değilseniz About Swagger Specification | Documentation | Swagger adresini ziyaret edebilirsiniz.

Kurulum

İlk olarak swagger komut satırı aracını indirin.

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

Ardından swagger kaynak kod bağımlılıklarını indirin.

go get github.com/swaggo/swag

TIP

Sorun yaşanmaması için her ikisinin de sürümü aynı olmalıdır.

Ardından swagger'ın statik dosya kütüphanesini indirin. html, css, js vb. her şey Go koduna gömülüdür.

go get github.com/swaggo/files@latest

Son olarak swagger'ın gin adaptör kütüphanesini indirin.

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

Bu makalede sadece gin örnek olarak kullanıldığından diğer web framework'leri için adaptörleri kendiniz inceleyebilirsiniz. Temelde hepsi benzerdir.

Kullanım

go mod kullanarak en temel Go projesini oluşturun. main.go dosyasını oluşturun ve aşağıdaki içeriği yazın.

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

Bu çok basit bir gin web örneğidir. main fonksiyonundaki yorumlar dokümantasyonun temel bilgileri Ping fonksiyonu ise sıradan bir API'dir. Ardından dokümantasyonu oluşturmak için komutu çalıştırın. Varsayılan olarak main.go ile aynı dizindeki docs klasöründe oluşturulur.

swag init

main.go kodunu değiştirin.

go
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    // Oluşturulan API dokümantasyon paketini anonim olarak içe aktar
    _ "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 statik dosya yönlendirmesini kaydet
    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")),
    })
}

Programı çalıştırın ve 127.0.0.1/swagger/index.html adresini ziyaret edin. Arayüz şu şekildedir:

Böylece temel bir API dokümantasyonu çalıştırılmış olur. Sonraki adımlarda bazı özel dikkat edilmesi gereken noktalar dışında diğer dillerle kullanımda büyük bir fark yoktur.

Parametreler

Parametre tanımlama formatı şöyledir:

@param name paramtype datatype isRequired comment

Bir örnek:

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

Desteklenen parametre türleri:

  • query
  • path
  • header
  • body
  • formData

Veri türleri:

  • string (string)
  • integer (int, uint, uint32, uint64)
  • number (float32)
  • boolean (bool)
  • kullanıcı tanımlı struct

Parametre türü kendi türünüz de olabilir. Önemli olan swagger tarafından taranabilmesidir.

Yanıt

API yanıtını tanımlama formatı şöyledir:

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

Durum kodu temel tür ve veri türünden oluşur. {array} bir dizi olduğunu belirtir ve veri türünün dizi formunu gösterir. {object} veri türünün orijinal formunu gösterir. Örneğin genellikle统一 bir yanıt gövdesi tanımlarız:

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

Data alanının türü belirsizdir. Yanıt örneklerini açıklarken aşağıdaki gibi birleştirebilirsiniz:

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

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

Modeller

Struct alanlarına eklenen yorumlar swagger tarafından model alan yorumu olarak taranır.

go
package model

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

example tag'inin değeri sayfada örnek değer olarak gösterilir. Elbette alan kısıtlamalarını da destekler:

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

Tüm modeller kullanılırken swagger tarafından taranabildiğinden emin olunmalıdır. Aksi takdirde çalışmaz.

Kimlik Doğrulama

Kimlik doğrulama bölümü şunları destekler:

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

Eğer API kimlik doğrulaması JWT kullanıyorsa ve Authorization header alanında saklanıyorsa aşağıdaki gibi tanımlayabiliriz:

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

Bu özünde sadece bir apikey'dir. Eğer bearer token gönderiyorsanız Bearer ön ekini manuel olarak eklemeniz gerekir.

Ardından kimlik doğrulaması gereken API'lere aşağıdaki yorumu ekleyin:

go
// @security Bearer

Değeri securityDefinitions tanımınızın adıdır.

Yapılandırma

swag özünde birden fazla farklı swagger örneğini bir map'te saklar. ginSwagger adaptör olarak doc.json yani API tanım dosyasını okur. swaggerFiles API tanımını ayrıştırmak ve arayüz oluşturmak için statik HTML dosyaları sağlar. Tüm süreci anladıktan sonra özel işlemler yapabilirsiniz.

go
// Name swag örneğini kaydetmek için kullanılan benzersiz bir addır.
// Varsayılan örnek adı
const Name = "swagger"

var (
  swaggerMu sync.RWMutex
    // Örnek tablosu
  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"
    }

    // swagger_index.html adında bir şablon oluştur
    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
       }

       // Yönlendirme eşleşmesi
       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 {
       // Ana sayfa
       case "index.html":
          _ = index.Execute(ctx.Writer, config.toSwaggerConfig())
       // API açıklama dosyası
       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)
       }
    }
}

Oluşturulan Go kodu aracılığıyla örnek kaydı otomatik olarak tamamlanır. Aşağıda otomatik olarak oluşturulan docs.go dosyasının bir kısmı:

go
// SwaggerInfo dışa aktarılan Swagger Info'yu tutar. Böylece istemciler değiştirebilir.
var SwaggerInfo = &swag.Spec{
  Version:          "",
  Host:             "",
  BasePath:         "",
  Schemes:          []string{},
  Title:            "",
  Description:      "",
  InfoInstanceName: "swagger",
  SwaggerTemplate:  docTemplate,
  LeftDelim:        "{{",
  RightDelim:       "}}",
}

func init() {
    // Örneği kaydet
  swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

init fonksiyonunda mevcut örneği kaydetmek için bir Register fonksiyonu olduğunu görebilirsiniz. Örnek adını değiştirmek istiyorsanız bu dosyada düzenleme yapmanız önerilmez. Çünkü docs.go dosyası otomatik olarak oluşturulur. Sadece kod oluştururken --instanceName appapi parametresini kullanmanız yeterlidir. Kolaylık için go generate komutunu Go dosyasına gömebilirsiniz. Böylece kod otomatik olarak oluşturulabilir:

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

Şahsen swagger'ın genel bilgi yorumlarını main.go veya main fonksiyonuna yazmayı sevmiyorum. Bu yorumları go generate'ın üstüne yazmak en uygunudur.

TIP

Birden fazla örnek gerekiyorsa örnek adlarının benzersiz olduğundan emin olun. Aksi takdirde panic oluşur.

Bazı yapılandırmaları özelleştirmek için ginSwagger.CustomWrapHandler kullanılmalıdır. Öncekinden farklı olarak bir Config parametresi vardır. Açıklaması şöyledir:

go
// Config stores ginSwagger configuration variables.
type Config struct {
  // API tanımına işaret eden URL (genellikle swagger.json veya swagger.yaml). Varsayılan `doc.json`.
  URL                      string
    // API listesinin açık durumu
  DocExpansion             string
    // Örnek adı
  InstanceName             string
    // Başlık
  Title                    string
    // Açılma derinliği
  DefaultModelsExpandDepth int
    // Adından anlaşılabilir
  DeepLinking              bool
  PersistAuthorization     bool
  Oauth2DefaultClientID    string
}

Varsayılan Handler yerine swaggerFiles.NewHandler() kullanın. Özellikle birden fazla örnek olduğunda böyle yapılmalıdır.

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

Bunun dışında tür yeniden yazma vb. işlemler de yapılabilir. Hepsi oldukça basittir. Daha fazla içerik için resmi dokümantasyonu okuyabilirsiniz.

Dikkat Edilmesi Gerekenler

  1. swag yorumlardan openapi API açıklama dosyası oluşturur. Oluştururken belirtilen dizinin API dokümantasyonunun temel bilgilerini içermesi gerekir. Varsayılan olarak main.go dosyasında aranır.

  2. swag init varsayılan olarak mevcut dizini belirtir. Değeri ./'dir. Birden fazla dizin belirtmek için swag init -d kullanılabilir. Virgülle ayrılır. İlk belirtilen dizin API dokümantasyonunun temel bilgilerini içermelidir. Örneğin:

    swag init -d ./,./api
  3. -g API dokümantasyonunun temel bilgilerinin saklandığı dosyanın adı özelleştirilebilir. Varsayılan main.go'dır. Dokümantasyon oluştururken dosya adını belirtmek için -g parametresi kullanılır:

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

    Bu komut ./api.go dosyasında API dokümantasyonunun temel bilgilerini ayrıştırır. Aynı zamanda ./ ve ./api dizinlerinde diğer API yorumlarını arar ve ayrıştırır ve ilgili dokümantasyonu oluşturur.

  4. -o parametresi dokümantasyon açıklama dosyasının çıktı yolunu belirtebilir. Varsayılan ./docs'tur. Örneğin:

    swag init -o ./api/docs
  5. --ot çıktı dosyası türünü belirtebilir. Varsayılan (docs.go,swagger.json,swagger.yaml)'dır. Swagger UI'i Go programı ile yüklemek istiyorsanız go dosyası gereklidir:

    swag init --ot go,yaml

    Oluşturulan json ve yaml dosyaları diğer API yönetim yazılımlarında veri içe aktarmak için uygundur.

  6. Yorumların nerede yazıldığı fark etmez. Fonksiyonda yazılmasa bile ayrıştırılabilir. Sadece fonksiyonda yazıldığında okunabilirlik daha iyidir. Özünde yorum formu ve Go kaynak koduna gömülü bir DSL'dir.

  7. swag birçok başka parametreyi de destekler. swag init -h ile görüntüleyebilirsiniz.

Golang by www.golangdev.cn edit