swag
swaggo/swag est une implémentation de Swagger API 2.0 pour le langage Go. En écrivant des commentaires dans un format spécifique, on peut générer des documents d'interface de type swagger.json et swagger.yaml, faciles à exporter et importer.
Dépôt : swaggo/swag: Automatically generate RESTful API documentation with Swagger 2.0 for Go. (github.com)
Documentation : swaggo/swag: Automatically generate RESTful API documentation with Swagger 2.0 for Go. (github.com)
Les frameworks web supportés par défaut par swag sont listés ci-dessous. Cet article utilise gin comme exemple pour démontrer la génération rapide de documentation d'API avec gin combiné à swagger.
TIP
Si vous n'êtes pas familier avec la syntaxe swagger, vous pouvez consulter About Swagger Specification | Documentation | Swagger
Installation
D'abord, télécharger l'outil en ligne de commande swagger
go install github.com/swaggo/swag/cmd/swag@latestEnsuite, télécharger la dépendance du code source swagger
go get github.com/swaggo/swagTIP
Pour éviter les problèmes, les deux versions doivent rester identiques.
Puis télécharger la bibliothèque de fichiers statiques swagger. Les fichiers HTML, CSS, JS, etc. sont intégrés dans le code Go.
go get github.com/swaggo/files@latestEnfin, télécharger la bibliothèque d'adaptation swagger pour gin
go get github.com/swaggo/gin-swagger@latestComme cet article utilise uniquement gin comme exemple, veuillez vous renseigner vous-même pour les adaptateurs d'autres frameworks web, le principe reste globalement le même.
Utilisation
Utiliser go mod pour créer un projet Go basique, créer un nouveau fichier main.go, et y écrire le contenu suivant.
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")),
})
}C'est un exemple très simple de gin web. Les commentaires au-dessus de la fonction main sont les informations de base du document, et la fonction Ping est une interface ordinaire. Ensuite, exécutez la commande pour générer le document, par défaut dans le répertoire docs au même niveau que main.go.
swag initModifier le code de main.go
package main
import (
"fmt"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
// Import anonyme du package de documentation d'API généré
_ "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()
// Enregistrer la route de fichiers statiques 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")),
})
}Lancer le programme, accéder à 127.0.0.1/swagger/index.html, l'interface s'affiche comme suit

Ainsi, une documentation d'API basique est opérationnelle. Ensuite, à part quelques points particuliers à noter, l'utilisation est globalement similaire à celle dans d'autres langages.
Paramètres
Le format pour définir les paramètres est
@param name paramtype datatype isRequired commentUn exemple est le suivant
@param userId query int true "user unique id"Les types de paramètres supportés sont
- query
- path
- header
- body
- formData
Les types de données sont
- string (string)
- integer (int, uint, uint32, uint64)
- number (float32)
- boolean (bool)
- user defined struct
Le type de paramètre peut aussi être votre propre type, à condition qu'il puisse être scanné par swagger.
Réponses
Le format de base pour définir les réponses d'interface est le suivant
// @Success 200 {array} model.Account
// @Failure 400 {object} httputil.HTTPError
// @Failure 404 {object} httputil.HTTPError
// @Failure 500 {object} httputil.HTTPErrorComposé du code de statut, du type de base et du type de données. {array} indique un tableau, qui affichera la forme tableau du type de données, {object} affichera la forme originale du type de données. Par exemple, nous définissons généralement un corps de réponse unifié
type JSONResult struct {
Code int `json:"code" `
Message string `json:"message"`
Data interface{} `json:"data"`
}Le type du champ Data est incertain, lors de la description de la réponse, vous pouvez le combiner comme suit
// Combinaison
@success 200 {object} jsonresult.JSONResult{data=Account} "desc"
// Tableau
@success 200 {object} jsonresult.JSONResult{data=[]Account} "desc"Modèles
Ajouter des commentaires aux champs de structure sera scanné par swagger comme commentaires de champs de modèle
package model
type Account struct {
// account id
ID int `json:"id" example:"1"`
// username
Name string `json:"name" example:"account name"`
}La valeur du tag example sera affichée comme exemple dans la page. Bien sûr, il supporte aussi les contraintes de champs
type Foo struct {
Bar string `minLength:"4" maxLength:"16"`
Baz int `minimum:"10" maximum:"20" default:"15"`
Qux []string `enums:"foo,bar,baz"`
}Tous les modèles utilisés doivent s'assurer qu'ils peuvent être scannés par swagger, sinon ils ne fonctionneront pas.
Authentification
Pour l'authentification, cela supporte
- Basic Auth
- API Key
- OAuth2 app auth
- OAuth2 implicit auth
- OAuth2 password auth
- OAuth2 access code auth
Si l'authentification de l'interface utilise JWT, stocké dans le champ Authorization du header, nous pouvons définir comme suit
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
Essentiellement, ce n'est qu'une apikey, si vous passez un bearer token, vous devez ajouter manuellement le préfixe Bearer.

Puis ajoutez le commentaire suivant sur les interfaces nécessitant une authentification
// @security BearerSa valeur est le nom que vous avez défini dans securityDefinitions.
Configuration
swag stocke en fait plusieurs instances swagger différentes dans une map, ginSwagger comme adaptateur lit doc.json depuis l'instance (le fichier de définition de l'API), swaggerFiles fournit les fichiers HTML statiques pour afficher la page web, analyse la définition de l'API et génère l'interface. Une fois le processus compris, vous pouvez effectuer des opérations personnalisées.
// Name is a unique name be used to register swag instance.
// Nom d'instance par défaut
const Name = "swagger"
var (
swaggerMu sync.RWMutex
// Table d'instances
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"
}
// create a template with name
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
}
// Correspondance de 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 {
// Page d'accueil
case "index.html":
_ = index.Execute(ctx.Writer, config.toSwaggerConfig())
// Fichier de description 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)
}
}
}L'enregistrement automatique des instances se fait via le code Go généré. Ci-dessous, une partie du code de docs.go généré automatiquement
// 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() {
// Enregistrer l'instance
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}On peut voir que dans la fonction init, il y a une fonction Register pour enregistrer l'instance courante. Si vous voulez modifier le nom de l'instance, il n'est pas recommandé de modifier ce fichier car docs.go est généré automatiquement. Il suffit d'utiliser le paramètre --instanceName appapi lors de la génération du code. Pour plus de commodité, vous pouvez utiliser la commande go generate intégrée dans les fichiers go pour faciliter la génération automatique de code, comme ci-dessous.
// 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 ./swaggerPersonnellement, je n'aime pas écrire les commentaires d'informations générales swagger dans main.go ou sur la fonction main. Écrire ces commentaires au-dessus de go generate est le plus approprié.
TIP
Si vous avez besoin de plusieurs instances, assurez-vous que les noms d'instances sont uniques, sinon il y aura un panic
Pour personnaliser certaines configurations, vous devez utiliser ginSwagger.CustomWrapHandler, qui a un paramètre Config supplémentaire par rapport au précédent, dont la signification est la suivante
// Config stores ginSwagger configuration variables.
type Config struct {
// The url pointing to API definition (normally swagger.json or swagger.yaml). Default is `doc.json`.
URL string
// État d'expansion de la liste d'interfaces
DocExpansion string
// Nom de l'instance
InstanceName string
// Titre
Title string
// Profondeur d'expansion
DefaultModelsExpandDepth int
// Comme son nom l'indique
DeepLinking bool
PersistAuthorization bool
Oauth2DefaultClientID string
}Utilisez swaggerFiles.NewHandler() pour remplacer le Handler par défaut, surtout nécessaire dans le cas d'instances multiples.
engine.GET(openapi.ApiDoc, ginSwagger.CustomWrapHandler(openapi.Config, swaggerFiles.NewHandler()))De plus, vous pouvez effectuer une réécriture de type et d'autres opérations, qui sont relativement simples. Pour plus de contenu, vous pouvez consulter la documentation officielle.
Points d'attention
swag génère le fichier de description openapi basé sur les commentaires. Lors de la génération, le répertoire spécifié doit contenir les informations de base de la documentation d'interface, par défaut recherchées dans
main.goswag initspécifie par défaut le répertoire courant, dont la valeur est./, vous pouvez utiliserswag init -dpour spécifier plusieurs répertoires, séparés par des virgules. Le premier répertoire spécifié doit contenir les informations de base de la documentation d'interface. Par exempleswag init -d ./,./api-g, le fichier de stockage des informations de base de la documentation d'interface peut avoir un nom de fichier personnalisé, par défautmain.go. Lors de la génération de la documentation, utilisez le paramètre-gpour spécifier le nom du fichierswag init -g api.go -d ./,./apiCette commande signifie analyser les informations de base de la documentation d'interface dans
./api.go, et rechercher et analyser les commentaires des autres interfaces dans les deux répertoires./et./apipour générer la documentation correspondante.Le paramètre
-opeut spécifier le chemin de sortie des fichiers de description de documentation, par défaut./docs, par exemple :swag init -o ./api/docs--otpeut spécifier le type de fichiers de sortie, par défaut (docs.go, swagger.json, swagger.yaml), si vous voulez utiliser un programme go pour charger swagger ui, le fichier go est indispensable.swag init --ot go,yamlLes fichiers json et yaml générés peuvent être facilement importés dans d'autres logiciels de gestion d'API.
Les commentaires peuvent être écrits n'importe où, même s'ils ne sont pas écrits sur une fonction, ils peuvent être analysés. Les écrire sur une fonction améliore juste la lisibilité. Essentiellement, c'est un DSL intégré au code source go sous forme de commentaires.
swag supporte encore beaucoup d'autres paramètres, vous pouvez utiliser
swag init -hpour les voir.
