Ajout de Swagger à votre API Go

Générer automatiquement les documents OpenAPI à partir des annotations de code

Sommaire

La documentation d’API est cruciale pour toute application moderne, et pour les API Go Swagger, (OpenAPI) est devenu le standard de l’industrie. Pour les développeurs Go, swaggo offre une solution élégante pour générer une documentation d’API complète directement à partir des annotations du code.

spécifications swagger api sur un tableau agile Cette belle image est générée par le modèle IA Flux 1 dev.

Pourquoi Swagger est essentiel pour les API Go

Lors de la création d’API REST, la documentation devient souvent obsolète au fur et à mesure que le code évolue. Swagger résout ce problème en générant la documentation à partir de votre code source, garantissant ainsi qu’elle reste synchronisée avec votre implémentation. L’interface utilisateur interactive de Swagger permet aux développeurs de tester les points d’accès directement depuis le navigateur, améliorant considérablement l’expérience de développement.

Pour les équipes construisant des microservices ou des API publiques, la documentation Swagger devient essentielle pour :

  • Génération de clients : Créer automatiquement des bibliothèques de clients dans plusieurs langages
  • Tests de contrat : Valider les requêtes et les réponses par rapport aux schémas définis
  • Collaboration d’équipe : Fournir une source de vérité unique pour les contrats d’API
  • Intégration des nouveaux développeurs : Les nouveaux membres de l’équipe peuvent explorer les API de manière interactive

Démarrage avec swaggo

La bibliothèque swaggo est l’outil le plus populaire pour ajouter le support Swagger aux applications Go. Elle fonctionne en analysant des commentaires spéciaux dans votre code et en générant des fichiers de spécification OpenAPI 3.0.

Installation

Installez d’abord l’outil CLI swag :

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

Ensuite, ajoutez le package middleware Swagger approprié pour votre framework. Pour Gin :

go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files

Pour Echo :

go get -u github.com/swaggo/echo-swagger

Pour Fiber :

go get -u github.com/gofiber/swagger

Configuration de base

Commencez par ajouter les informations générales de l’API dans votre fichier main.go. De la même manière que vous structureriez une API REST en Go, les annotations doivent être claires et descriptives :

// @title           Product API
// @version         1.0
// @description     A product management API with Swagger documentation
// @termsOfService  http://swagger.io/terms/

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

// @license.name  Apache 2.0
// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html

// @host      localhost:8080
// @BasePath  /api/v1

// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.

func main() {
    // Your application code
}

Implémentation avec le Framework Gin

Implémentons un exemple complet en utilisant Gin. D’abord, définissez vos modèles de données avec des étiquettes de structure :```go type Product struct { ID int json:"id" example:"1" Name string json:"name" example:"Laptop" binding:"required" Description string json:"description" example:"High-performance laptop" Price float64 json:"price" example:"999.99" binding:"required,gt=0" Stock int json:"stock" example:"50" }

type ErrorResponse struct { Error string json:"error" example:"Invalid input" Message string json:"message" example:"Product name is required" }


Maintenant, annotez vos fonctions de traitement. Lors du travail avec des [opérations de base de données](https://www.glukhov.org/fr/app-architecture/data-access/comparing-go-orms-gorm-ent-bun-sqlc/ "Comparaison des ORM Go pour PostgreSQL : GORM vs Ent vs Bun vs sqlc - avec des exemples de code"), ces annotations aident à documenter le flux de données :

```go
// GetProduct godoc
// @Summary      Get product by ID
// @Description  Retrieve a single product by its unique identifier
// @Tags         products
// @Accept       json
// @Produce      json
// @Param        id   path      int  true  "Product ID"
// @Success      200  {object}  Product
// @Failure      400  {object}  ErrorResponse
// @Failure      404  {object}  ErrorResponse
// @Router       /products/{id} [get]
func GetProduct(c *gin.Context) {
    id := c.Param("id")
    // Implementation here
    c.JSON(200, Product{ID: 1, Name: "Laptop", Price: 999.99})
}

// CreateProduct godoc
// @Summary      Create a new product
// @Description  Add a new product to the catalog
// @Tags         products
// @Accept       json
// @Produce      json
// @Param        product  body      Product  true  "Product object"
// @Success      201      {object}  Product
// @Failure      400      {object}  ErrorResponse
// @Security     Bearer
// @Router       /products [post]
func CreateProduct(c *gin.Context) {
    var product Product
    if err := c.ShouldBindJSON(&product); err != nil {
        c.JSON(400, ErrorResponse{Error: "Bad Request", Message: err.Error()})
        return
    }
    // Save to database
    c.JSON(201, product)
}

Génération de la documentation

Après avoir annoté votre code, générez la documentation Swagger :

swag init

Cela crée un dossier docs contenant swagger.json, swagger.yaml et des fichiers Go. Importez et enregistrez le point d’accès Swagger :

package main

import (
    "github.com/gin-gonic/gin"
    swaggerFiles "github.com/swaggo/files"
    ginSwagger "github.com/swaggo/gin-swagger"
    
    _ "yourproject/docs" // Import generated docs
)

func main() {
    r := gin.Default()
    
    // API routes
    v1 := r.Group("/api/v1")
    {
        v1.GET("/products/:id", GetProduct)
        v1.POST("/products", CreateProduct)
    }
    
    // Swagger endpoint
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
    
    r.Run(":8080")
}

Accédez maintenant à votre documentation d’API interactive sur http://localhost:8080/swagger/index.html.

Implémentation avec le Framework Echo

Les utilisateurs d’Echo suivent un schéma similaire, mais avec des middlewares spécifiques à Echo :

package main

import (
    "github.com/labstack/echo/v4"
    echoSwagger "github.com/swaggo/echo-swagger"
    
    _ "yourproject/docs"
)

func main() {
    e := echo.New()
    
    // API routes
    api := e.Group("/api/v1")
    api.GET("/products/:id", getProduct)
    api.POST("/products", createProduct)
    
    // Swagger endpoint
    e.GET("/swagger/*", echoSwagger.WrapHandler)
    
    e.Start(":8080")
}

Implémentation avec le Framework Fiber

L’implémentation de Fiber est tout aussi simple :

package main

import (
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/swagger"
    
    _ "yourproject/docs"
)

func main() {
    app := fiber.New()
    
    // API routes
    api := app.Group("/api/v1")
    api.Get("/products/:id", getProduct)
    api.Post("/products", createProduct)
    
    // Swagger endpoint
    app.Get("/swagger/*", swagger.HandlerDefault)
    
    app.Listen(":8080")
}

Annotations Swagger avancées

Documenter des corps de requête complexes

Pour les structures imbriquées ou les tableaux :

type CreateOrderRequest struct {
    CustomerID int           `json:"customer_id" example:"123" binding:"required"`
    Items      []OrderItem   `json:"items" binding:"required,min=1"`
    ShippingAddress Address  `json:"shipping_address" binding:"required"`
}

type OrderItem struct {
    ProductID int `json:"product_id" example:"1" binding:"required"`
    Quantity  int `json:"quantity" example:"2" binding:"required,min=1"`
}

type Address struct {
    Street  string `json:"street" example:"123 Main St" binding:"required"`
    City    string `json:"city" example:"New York" binding:"required"`
    ZipCode string `json:"zip_code" example:"10001" binding:"required"`
}

// CreateOrder godoc
// @Summary      Create a new order
// @Description  Create an order with multiple items and shipping information
// @Tags         orders
// @Accept       json
// @Produce      json
// @Param        order  body      CreateOrderRequest  true  "Order details"
// @Success      201    {object}  Order
// @Failure      400    {object}  ErrorResponse
// @Failure      422    {object}  ErrorResponse
// @Security     Bearer
// @Router       /orders [post]
func CreateOrder(c *gin.Context) {
    // Implementation
}

Documenter les téléchargements de fichiers

// UploadImage godoc
// @Summary      Upload product image
// @Description  Upload an image file for a product
// @Tags         products
// @Accept       multipart/form-data
// @Produce      json
// @Param        id    path      int   true  "Product ID"
// @Param        file  formData  file  true  "Image file"
// @Success      200   {object}  map[string]string
// @Failure      400   {object}  ErrorResponse
// @Security     Bearer
// @Router       /products/{id}/image [post]
func UploadImage(c *gin.Context) {
    file, _ := c.FormFile("file")
    // Handle upload
}

Paramètres de requête et pagination

// ListProducts godoc
// @Summary      List products with pagination
// @Description  Get paginated list of products with optional filtering
// @Tags         products
// @Accept       json
// @Produce      json
// @Param        page      query     int     false  "Page number" default(1)
// @Param        page_size query     int     false  "Items per page" default(10)
// @Param        category  query     string  false  "Filter by category"
// @Param        min_price query     number  false  "Minimum price"
// @Param        max_price query     number  false  "Maximum price"
// @Success      200       {array}   Product
// @Failure      400       {object}  ErrorResponse
// @Router       /products [get]
func ListProducts(c *gin.Context) {
    // Implementation with pagination
}

Authentification et Sécurité

Documentez différentes méthodes d’authentification dans votre API. Pour les applications multi-locataires, une documentation d’authentification appropriée est cruciale :

Authentification par jeton Bearer

// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.

Authentification par clé API

// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
// @description API key for authentication

Authentification OAuth2

// @securitydefinitions.oauth2.application OAuth2Application
// @tokenUrl https://example.com/oauth/token
// @scope.write Grants write access
// @scope.admin Grants read and write access to administrative information

Authentification de base

// @securityDefinitions.basic BasicAuth

Appliquez la sécurité à des points d’accès spécifiques :

// @Security Bearer
// @Security ApiKeyAuth

Personnalisation de l’interface Swagger UI

Vous pouvez personnaliser l’apparence et le comportement de l’interface Swagger UI :

// Custom configuration
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json")
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))

// With custom title
r.GET("/swagger/*any", ginSwagger.WrapHandler(
    swaggerFiles.Handler,
    ginSwagger.URL("http://localhost:8080/swagger/doc.json"),
    ginSwagger.DefaultModelsExpandDepth(-1),
))

Pour désactiver Swagger en production :

if os.Getenv("ENV") != "production" {
    r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}

Intégration avec CI/CD

Automatisez la génération de la documentation Swagger dans votre pipeline CI/CD :

# GitHub Actions example
name: Generate Swagger Docs
on: [push]

jobs:
  swagger:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      
      - name: Install swag
        run: go install github.com/swaggo/swag/cmd/swag@latest
      
      - name: Generate Swagger docs
        run: swag init
      
      - name: Commit docs
        run: |
          git config user.name github-actions
          git config user.email github-actions@github.com
          git add docs/
          git commit -m "Update Swagger documentation" || exit 0
          git push

Bonnes pratiques

1. Style d’annotation cohérent

Maintenez un formatage cohérent sur tous les points d’accès :

// HandlerName godoc
// @Summary      Brief description (under 50 chars)
// @Description  Detailed description of what the endpoint does
// @Tags         resource-name
// @Accept       json
// @Produce      json
// @Param        name  location  type  required  "description"
// @Success      200   {object}  ResponseType
// @Failure      400   {object}  ErrorResponse
// @Router       /path [method]

2. Utiliser des exemples descriptifs

Ajoutez des exemples réalistes pour aider les consommateurs de l’API :

type User struct {
    ID        int       `json:"id" example:"1"`
    Email     string    `json:"email" example:"user@example.com"`
    CreatedAt time.Time `json:"created_at" example:"2025-01-15T10:30:00Z"`
}

3. Documenter tous les codes de réponse

Incluez tous les codes de statut HTTP possibles :

// @Success      200  {object}  Product
// @Success      201  {object}  Product
// @Failure      400  {object}  ErrorResponse "Bad Request"
// @Failure      401  {object}  ErrorResponse "Unauthorized"
// @Failure      403  {object}  ErrorResponse "Forbidden"
// @Failure      404  {object}  ErrorResponse "Not Found"
// @Failure      422  {object}  ErrorResponse "Validation Error"
// @Failure      500  {object}  ErrorResponse "Internal Server Error"

4. Versionner votre API

Utilisez un versionnement approprié dans le chemin de base :

// @BasePath  /api/v1

Et organisez votre code en conséquence :

v1 := r.Group("/api/v1")
v2 := r.Group("/api/v2")

5. Regrouper les points d’accès liés

Utilisez des étiquettes pour organiser logiquement les points d’accès :

// @Tags products
// @Tags orders
// @Tags users

6. Garder la documentation à jour

Exécutez swag init avant chaque engagement ou intégrez-le dans votre processus de construction :

#!/bin/bash
# pre-commit hook
swag init
git add docs/

Tester la documentation Swagger

Lors du travail avec des architectures serverless comme AWS Lambda, le test de votre documentation d’API devient encore plus important :

func TestSwaggerGeneration(t *testing.T) {
    // Verify swagger.json exists
    _, err := os.Stat("./docs/swagger.json")
    if err != nil {
        t.Fatal("swagger.json not found, run 'swag init'")
    }
    
    // Verify swagger endpoint responds
    r := setupRouter()
    w := httptest.NewRecorder()
    req, _ := http.NewRequest("GET", "/swagger/index.html", nil)
    r.ServeHTTP(w, req)
    
    assert.Equal(t, 200, w.Code)
}

Problèmes courants et solutions

La documentation ne se met pas à jour

Si les modifications n’apparaissent pas, assurez-vous de régénérer la documentation :

swag init --parseDependency --parseInternal

Le drapeau --parseDependency analyse les dépendances externes, et --parseInternal analyse les packages internes.

Types personnalisés non reconnus

Pour les types issus de packages externes, utilisez l’étiquette swaggertype :

type CustomTime struct {
    time.Time
}

func (CustomTime) SwaggerDoc() map[string]string {
    return map[string]string{
        "time": "RFC3339 timestamp",
    }
}

Ou utilisez l’étiquette swaggertype :

type Product struct {
    ID        int        `json:"id"`
    UpdatedAt CustomTime `json:"updated_at" swaggertype:"string" format:"date-time"`
}

Tableaux et énumérations

Documentez les types de tableau et les énumérations :

type Filter struct {
    Status []string `json:"status" enums:"active,inactive,pending"`
    Tags   []string `json:"tags"`
}

// @Param  status  query  string  false  "Status filter" Enums(active, inactive, pending)

Approches alternatives

Bien que swaggo soit le choix le plus populaire, d’autres options existent :

go-swagger

Une alternative plus complète mais plus complexe :

brew install go-swagger
swagger generate spec -o ./swagger.json

Fichiers OpenAPI manuels

Pour un contrôle total, écrivez manuellement des spécifications OpenAPI en YAML :

openapi: 3.0.0
info:
  title: Product API
  version: 1.0.0
paths:
  /products:
    get:
      summary: List products
      responses:
        '200':
          description: Success

Ensuite, servez-les avec :

r.StaticFile("/openapi.yaml", "./openapi.yaml")

Intégration avec l’IA et les LLMs

Lors de la création d’API qui s’intègrent à des services d’IA, une documentation appropriée devient cruciale. Par exemple, lors du travail avec des sorties structurées de LLMs, Swagger aide à documenter les schémas de requêtes et de réponses complexes :

type LLMRequest struct {
    Prompt      string            `json:"prompt" example:"Summarize this text"`
    Model       string            `json:"model" example:"qwen2.5:latest"`
    Temperature float64           `json:"temperature" example:"0.7" minimum:"0" maximum:"2"`
    MaxTokens   int               `json:"max_tokens" example:"1000" minimum:"1"`
    Schema      map[string]interface{} `json:"schema,omitempty"`
}

// GenerateStructured godoc
// @Summary      Generate structured LLM output
// @Description  Generate text with constrained output schema
// @Tags         llm
// @Accept       json
// @Produce      json
// @Param        request  body      LLMRequest  true  "LLM parameters"
// @Success      200      {object}  map[string]interface{}
// @Failure      400      {object}  ErrorResponse
// @Router       /llm/generate [post]
func GenerateStructured(c *gin.Context) {
    // Implementation
}

Considérations de performance

La documentation Swagger a un impact de performance minimal :

  • Temps de construction : swag init prend 1 à 3 secondes pour la plupart des projets
  • Temps d’exécution : La documentation est chargée une seule fois au démarrage
  • Mémoire : Ajoute généralement 1-2 Mo à la taille du binaire
  • Temps de réponse : Aucun impact sur les points d’accès de l’API eux-mêmes

Pour les très grandes API (plus de 100 points d’accès), envisagez :

  • Le découpage en plusieurs fichiers Swagger
  • Le chargement paresseux des assets de l’interface Swagger UI
  • La fourniture de la documentation depuis un service séparé

Considérations de sécurité

Lors de l’exposition de la documentation Swagger :

  1. Désactiver en production (si l’API est interne) :
if os.Getenv("ENV") == "production" {
    // Don't register Swagger endpoint
    return
}
  1. Ajouter l’authentification :
authorized := r.Group("/swagger")
authorized.Use(AuthMiddleware())
authorized.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
  1. Mettre en place une limite de débit sur le point d’accès :
r.GET("/swagger/*any", RateLimitMiddleware(), ginSwagger.WrapHandler(swaggerFiles.Handler))
  1. Ne jamais exposer de détails internes :
  • Ne documentez pas les points d’accès internes
  • Évitez d’exposer directement les schémas de base de données
  • Nettoyez les messages d’erreur dans la documentation

Conclusion

L’ajout de la documentation Swagger à votre API Go transforme l’expérience de développement d’une approche basée sur la conjecture à une exploration guidée. La bibliothèque swaggo simplifie ce processus en générant une documentation OpenAPI complète à partir de vos annotations de code.

Points clés à retenir :

  • Commencez par des annotations de base et développez-les progressivement
  • Gardez la documentation synchronisée avec le code via CI/CD
  • Utilisez l’interface Swagger UI pour des tests interactifs pendant le développement
  • Documentez en détail l’authentification, les erreurs et les cas limites
  • Tenez compte des implications de sécurité lors de l’exposition de la documentation

Que vous construisiez des microservices, des API publiques ou des outils internes, la documentation Swagger rapporte des dividendes sous forme de réduction de la charge de support, d’intégration plus rapide et d’une meilleure conception d’API. L’investissement initial pour apprendre la syntaxe d’annotation devient rapidement une routine, et la génération automatisée garantit que votre documentation ne retarde jamais par rapport à votre implémentation.

Pour les développeurs Go, la combinaison de la typage fort, de la génération de code et du système d’annotation de swaggo crée un flux de travail puissant qui rend la documentation d’API une partie naturelle du processus de développement plutôt qu’un après-coup.

Si la pile HTTP sous-jacente est toujours une question ouverte, Frameworks Web Go en 2026 : net/http, chi, Gin, Echo, Fiber Comparés compare les cinq options sur la même charge de travail, de sorte que la décision du framework peut être réglée avant que les outils de documentation ne soient câblés.

Liens utiles

Ressources externes

S'abonner

Recevez de nouveaux articles sur les systèmes, l'infrastructure et l'ingénierie IA.