Agregar Swagger a tu API de Go
Generación automática de documentación OpenAPI desde anotaciones del código
La documentación de la API es crucial para cualquier aplicación moderna, y para las APIs de Go con Swagger (OpenAPI) se ha convertido en el estándar de la industria. Para los desarrolladores de Go, swaggo ofrece una solución elegante para generar una documentación de la API exhaustiva directamente desde las anotaciones del código.
Esta buena imagen es generada por el modelo de IA Flux 1 dev.
Por qué Swagger es importante para las APIs de Go
Al construir APIs REST, la documentación a menudo se desactualiza a medida que el código evoluciona. Swagger resuelve esto generando la documentación desde su código fuente, asegurando que se mantenga sincronizada con su implementación. La interfaz interactiva de Swagger permite a los desarrolladores probar los puntos de conexión directamente desde el navegador, mejorando significativamente la experiencia del desarrollador.
Para los equipos que construyen microservicios o APIs públicas, la documentación de Swagger se vuelve esencial para:
- Generación de clientes: Crear automáticamente bibliotecas de cliente en múltiples lenguajes
- Pruebas de contrato: Validar solicitudes y respuestas contra esquemas definidos
- Colaboración en equipo: Proporcionar una única fuente de verdad para los contratos de la API
- Onboarding de desarrolladores: Los nuevos miembros del equipo pueden explorar las APIs de forma interactiva
Primeros pasos con swaggo
La biblioteca swaggo es la herramienta más popular para añadir soporte de Swagger a las aplicaciones de Go. Funciona analizando comentarios especiales en su código y generando archivos de especificación OpenAPI 3.0.
Instalación
Primero, instale la herramienta CLI de swag:
go install github.com/swaggo/swag/cmd/swag@latest
Luego añada el paquete de middleware de Swagger apropiado para su marco de trabajo. Para Gin:
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
Para Echo:
go get -u github.com/swaggo/echo-swagger
Para Fiber:
go get -u github.com/gofiber/swagger
Configuración básica
Comience añadiendo información general de la API en su archivo main.go. De manera similar a cómo estructuraría una API REST en Go, las anotaciones deben ser claras y descriptivas:
// @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
}
Implementación con el marco Gin
Implementemos un ejemplo completo usando Gin. Primero, defina sus modelos de datos con etiquetas de estructura:```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"
}
Ahora anote sus funciones manejadoras. Al trabajar con [operaciones de base de datos](https://www.glukhov.org/es/app-architecture/data-access/comparing-go-orms-gorm-ent-bun-sqlc/ "Comparación de ORMs de Go para PostgreSQL: GORM vs Ent vs Bun vs sqlc - con ejemplos de código"), estas anotaciones ayudan a documentar el flujo de datos:
```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)
}
Generación de la documentación
Después de anotar su código, genere la documentación de Swagger:
swag init
Esto crea una carpeta docs con swagger.json, swagger.yaml y archivos de Go. Importe y registre el punto de conexión de 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")
}
Ahora acceda a su documentación de la API interactiva en http://localhost:8080/swagger/index.html.
Implementación con el marco Echo
Los usuarios de Echo siguen un patrón similar pero con el middleware específico de 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")
}
Implementación con el marco Fiber
La implementación de Fiber es igualmente sencilla:
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")
}
Anotaciones avanzadas de Swagger
Documentación de cuerpos de solicitud complejos
Para estructuras anidadas o matrices:
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
}
Documentación de cargas de archivos
// 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
}
Parámetros de consulta y paginación
// 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
}
Autenticación y seguridad
Documente diferentes métodos de autenticación en su API. Para las aplicaciones multi-inquilino, la documentación de autenticación adecuada es crucial:
Autenticación con Token Bearer
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
Autenticación con clave de API
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
// @description API key for authentication
Autenticación 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
Autenticación básica
// @securityDefinitions.basic BasicAuth
Aplique la seguridad a puntos de conexión específicos:
// @Security Bearer
// @Security ApiKeyAuth
Personalización de la interfaz de Swagger
Puede personalizar la apariencia y el comportamiento de la interfaz de Swagger:
// 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),
))
Para deshabilitar Swagger en producción:
if os.Getenv("ENV") != "production" {
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
Integración con CI/CD
Automatice la generación de la documentación de Swagger en su pipeline de 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
Mejores prácticas
1. Estilo de anotación consistente
Mantenga un formato consistente en todos los puntos de conexión:
// 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. Utilizar ejemplos descriptivos
Añada ejemplos realistas para ayudar a los consumidores de la 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. Documentar todos los códigos de respuesta
Incluya todos los posibles códigos de estado HTTP:
// @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. Versionar su API
Utilice la numeración de versiones adecuada en la ruta base:
// @BasePath /api/v1
Y organice su código en consecuencia:
v1 := r.Group("/api/v1")
v2 := r.Group("/api/v2")
5. Agrupar puntos de conexión relacionados
Use etiquetas para organizar los puntos de conexión lógicamente:
// @Tags products
// @Tags orders
// @Tags users
6. Mantener la documentación actualizada
Ejecute swag init antes de cada commit o intégralo en su proceso de compilación:
#!/bin/bash
# pre-commit hook
swag init
git add docs/
Pruebas de la documentación de Swagger
Al trabajar con arquitecturas serverless como AWS Lambda, probar su documentación de la API se vuelve aún más importante:
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)
}
Problemas comunes y soluciones
La documentación no se actualiza
Si los cambios no aparecen, asegúrese de que está regenerando la documentación:
swag init --parseDependency --parseInternal
La bandera --parseDependency analiza dependencias externas, y --parseInternal analiza paquetes internos.
Tipos personalizados no reconocidos
Para tipos de paquetes externos, use la etiqueta swaggertype:
type CustomTime struct {
time.Time
}
func (CustomTime) SwaggerDoc() map[string]string {
return map[string]string{
"time": "RFC3339 timestamp",
}
}
O use la etiqueta swaggertype:
type Product struct {
ID int `json:"id"`
UpdatedAt CustomTime `json:"updated_at" swaggertype:"string" format:"date-time"`
}
Matrices y enumeraciones
Documente los tipos de matriz y las enumeraciones:
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)
Enfoques alternativos
Si bien swaggo es la opción más popular, existen otras opciones:
go-swagger
Una alternativa más completa pero compleja:
brew install go-swagger
swagger generate spec -o ./swagger.json
Archivos OpenAPI manuales
Para un control total, escriba especificaciones OpenAPI manualmente en YAML:
openapi: 3.0.0
info:
title: Product API
version: 1.0.0
paths:
/products:
get:
summary: List products
responses:
'200':
description: Success
Y sírvala con:
r.StaticFile("/openapi.yaml", "./openapi.yaml")
Integración con IA y LLMs
Al construir APIs que se integran con servicios de IA, la documentación adecuada se vuelve crucial. Por ejemplo, al trabajar con salidas estructuradas de LLMs, Swagger ayuda a documentar esquemas de solicitud y respuesta complejos:
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
}
Consideraciones de rendimiento
La documentación de Swagger tiene un impacto de rendimiento mínimo:
- Tiempo de compilación:
swag inittoma de 1 a 3 segundos para la mayoría de los proyectos - Tiempo de ejecución: La documentación se carga una vez al inicio
- Memoria: Típicamente añade de 1 a 2 MB al tamaño del binario
- Tiempo de respuesta: Sin impacto en los propios puntos de conexión de la API
Para APIs muy grandes (100+ puntos de conexión), considere:
- Dividir en múltiples archivos de Swagger
- Carga diferida de los activos de la interfaz de Swagger
- Servir la documentación desde un servicio separado
Consideraciones de seguridad
Al exponer la documentación de Swagger:
- Deshabilitar en Producción (si la API es interna):
if os.Getenv("ENV") == "production" {
// Don't register Swagger endpoint
return
}
- Añadir Autenticación:
authorized := r.Group("/swagger")
authorized.Use(AuthMiddleware())
authorized.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
- Limitar la tasa del punto de conexión:
r.GET("/swagger/*any", RateLimitMiddleware(), ginSwagger.WrapHandler(swaggerFiles.Handler))
- Nunca exponer detalles internos:
- No documente puntos de conexión internos
- Evite exponer esquemas de base de datos directamente
- Sanitice los mensajes de error en la documentación
Conclusión
Añadir documentación de Swagger a su API de Go transforma la experiencia del desarrollador de un proceso de conjeturas a una exploración guiada. La biblioteca swaggo hace este proceso sencillo generando documentación OpenAPI exhaustiva desde sus anotaciones de código.
Puntos clave:
- Comience con anotaciones básicas y amplíe gradualmente
- Mantenga la documentación sincronizada con el código a través de CI/CD
- Utilice la interfaz de Swagger para pruebas interactivas durante el desarrollo
- Documente a fondo la autenticación, los errores y los casos extremos
- Considere las implicaciones de seguridad al exponer la documentación
Ya sea que esté construyendo microservicios, APIs públicas o herramientas internas, la documentación de Swagger da frutos en la reducción de la carga de soporte, el onboarding más rápido y un mejor diseño de la API. La inversión inicial en aprender la sintaxis de anotación se convierte rápidamente en una rutina, y la generación automatizada asegura que su documentación nunca se quede atrás con su implementación.
Para los desarrolladores de Go, la combinación de tipado fuerte, generación de código y el sistema de anotaciones de swaggo crea un flujo de trabajo poderoso que convierte la documentación de la API en una parte natural del proceso de desarrollo en lugar de una última consideración.
Si la pila de HTTP subyacente aún es una pregunta abierta, Marcos de trabajo web de Go en 2026: net/http, chi, Gin, Echo, Fiber comparados compara las cinco opciones con la misma carga de trabajo, por lo que la decisión del marco de trabajo puede tomarse antes de integrar las herramientas de documentación.
Enlaces útiles
- Hoja de referencia de Go
- Construir APIs REST en Go
- Marcos de trabajo web de Go en 2026: net/http, chi, Gin, Echo, Fiber comparados
- Comparando ORMs de Go para PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Patrones de base de datos multi-inquilino con ejemplos en Go
- LLMs con salida estructurada: Ollama, Qwen3 y Python o Go
- Rendimiento de AWS lambda: JavaScript vs Python vs Golang