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@latestArdından swagger kaynak kod bağımlılıklarını indirin.
go get github.com/swaggo/swagTIP
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@latestSon olarak swagger'ın gin adaptör kütüphanesini indirin.
go get github.com/swaggo/gin-swagger@latestBu 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.
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 initmain.go kodunu değiştirin.
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 commentBir örnek:
@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:
// @Success 200 {array} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPErrorDurum 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:
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:
// 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.
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:
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:
// @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:
// @security BearerDeğ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.
// 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
)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ı:
// 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:
// 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:
// 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.
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
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.godosyasında aranır.swag initvarsayılan olarak mevcut dizini belirtir. Değeri./'dir. Birden fazla dizin belirtmek içinswag init -dkullanılabilir. Virgülle ayrılır. İlk belirtilen dizin API dokümantasyonunun temel bilgilerini içermelidir. Örneğin:swag init -d ./,./api-gAPI dokümantasyonunun temel bilgilerinin saklandığı dosyanın adı özelleştirilebilir. Varsayılanmain.go'dır. Dokümantasyon oluştururken dosya adını belirtmek için-gparametresi kullanılır:swag init -g api.go -d ./,./apiBu komut
./api.godosyasında API dokümantasyonunun temel bilgilerini ayrıştırır. Aynı zamanda./ve./apidizinlerinde diğer API yorumlarını arar ve ayrıştırır ve ilgili dokümantasyonu oluşturur.-oparametresi dokümantasyon açıklama dosyasının çıktı yolunu belirtebilir. Varsayılan./docs'tur. Örneğin:swag init -o ./api/docs--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,yamlOluşturulan json ve yaml dosyaları diğer API yönetim yazılımlarında veri içe aktarmak için uygundur.
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.
swag birçok başka parametreyi de destekler.
swag init -hile görüntüleyebilirsiniz.
