Swagger zu Ihrer Go-API hinzufügen
OpenAPI-Dokumentation automatisch aus Code-Anmerkungen generieren
API-Dokumentation ist entscheidend für jede moderne Anwendung, und für Go APIs Swagger (OpenAPI) hat sich zum Branchenstandard entwickelt. Für Go-Entwickler bietet swaggo eine elegante Lösung, um umfassende API-Dokumentation direkt aus Code-Anmerkungen zu generieren.
Dieses schöne Bild wurde von AI-Modell Flux 1 dev generiert.
Warum Swagger für Go-APIs wichtig ist
Beim Erstellen von REST-APIs wird die Dokumentation oft veraltet, wenn sich der Code weiterentwickelt. Swagger löst dieses Problem, indem es die Dokumentation aus dem Quellcode generiert und so sicherstellt, dass sie mit der Implementierung synchron bleibt. Die interaktive Swagger-Benutzeroberfläche ermöglicht es Entwicklern, Endpunkte direkt im Browser zu testen, was die Entwicklererfahrung erheblich verbessert.
Für Teams, die Microservices oder öffentliche APIs entwickeln, wird Swagger-Dokumentation zu einem wesentlichen Element für:
- Client-Generierung: Automatische Erstellung von Client-Bibliotheken in mehreren Sprachen
- Vertragstests: Validierung von Anfragen und Antworten gegen definierte Schemas
- Teamzusammenarbeit: Bereitstellung einer einzigen Wissensquelle für API-Verträge
- Einführung neuer Entwickler: Neue Teammitglieder können APIs interaktiv erkunden
Einstieg in swaggo
Die swaggo-Bibliothek ist das beliebteste Tool zur Hinzufügung von Swagger-Unterstützung zu Go-Anwendungen. Sie funktioniert, indem sie spezielle Kommentare im Code analysiert und OpenAPI 3.0-Spezifikationsdateien generiert.
Installation
Installieren Sie zunächst das swag-CLI-Tool:
go install github.com/swaggo/swag/cmd/swag@latest
Fügen Sie dann das entsprechende Swagger-Middleware-Paket für Ihr Framework hinzu. Für Gin:
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
Für Echo:
go get -u github.com/swaggo/echo-swagger
Für Fiber:
go get -u github.com/gofiber/swagger
Grundlegende Konfiguration
Beginnen Sie mit der Hinzufügung allgemeiner API-Informationen in Ihrer main.go-Datei. Ähnlich wie bei der Strukturierung einer REST-API in Go, sollten die Annotationen klar und beschreibend sein:
// @title Produkt-API
// @version 1.0
// @description Eine Produktverwaltungs-API mit Swagger-Dokumentation
// @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 Geben Sie "Bearer" gefolgt von einem Leerzeichen und JWT-Token ein.
func main() {
// Ihr Anwendungscode
}
Implementierung mit dem Gin-Framework
Lassen Sie uns ein vollständiges Beispiel mit Gin implementieren. Definieren Sie zunächst Ihre Datenmodelle mit Struct-Tags:
type Product struct {
ID int `json:"id" example:"1"`
Name string `json:"name" example:"Laptop" binding:"required"`
Description string `json:"description" example:"Hochleistungs-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:"Ungültige Eingabe"`
Message string `json:"message" example:"Produktname ist erforderlich"`
}
Annotieren Sie nun Ihre Handler-Funktionen. Bei der Arbeit mit Datenbankoperationen, helfen diese Annotationen bei der Dokumentation des Datenflusses:
// GetProduct godoc
// @Summary Produkt nach ID abrufen
// @Description Abrufen eines einzelnen Produkts anhand seiner eindeutigen Kennung
// @Tags products
// @Accept json
// @Produce json
// @Param id path int true "Produkt-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")
// Implementierung hier
c.JSON(200, Product{ID: 1, Name: "Laptop", Price: 999.99})
}
// CreateProduct godoc
// @Summary Erstellen eines neuen Produkts
// @Description Hinzufügen eines neuen Produkts zum Katalog
// @Tags products
// @Accept json
// @Produce json
// @Param product body Product true "Produkt-Objekt"
// @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
}
// Speichern in der Datenbank
c.JSON(201, product)
}
Generieren von Dokumentation
Nach dem Annotieren Ihres Codes generieren Sie die Swagger-Dokumentation:
swag init
Dies erstellt einen docs-Ordner mit swagger.json, swagger.yaml und Go-Dateien. Importieren und registrieren Sie den Swagger-Endpunkt:
package main
import (
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
_ "yourproject/docs" // Importierte generierte Dokumente
)
func main() {
r := gin.Default()
// API-Routen
v1 := r.Group("/api/v1")
{
v1.GET("/products/:id", GetProduct)
v1.POST("/products", CreateProduct)
}
// Swagger-Endpunkt
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
r.Run(":8080")
}
Greifen Sie nun auf Ihre interaktive API-Dokumentation zu unter http://localhost:8080/swagger/index.html.
Implementierung mit dem Echo-Framework
Echo-Nutzer folgen einem ähnlichen Muster, jedoch mit Echo-spezifischem Middleware:
package main
import (
"github.com/labstack/echo/v4"
echoSwagger "github.com/swaggo/echo-swagger"
_ "yourproject/docs"
)
func main() {
e := echo.New()
// API-Routen
api := e.Group("/api/v1")
api.GET("/products/:id", getProduct)
api.POST("/products", createProduct)
// Swagger-Endpunkt
e.GET("/swagger/*", echoSwagger.WrapHandler)
e.Start(":8080")
}
Implementierung mit dem Fiber-Framework
Die Implementierung von Fiber ist ebenso einfach:
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/swagger"
_ "yourproject/docs"
)
func main() {
app := fiber.New()
// API-Routen
api := app.Group("/api/v1")
api.Get("/products/:id", getProduct)
api.Post("/products", createProduct)
// Swagger-Endpunkt
app.Get("/swagger/*", swagger.HandlerDefault)
app.Listen(":8080")
}
Fortgeschrittene Swagger-Annotationen
Dokumentation komplexer Anforderungsbodies
Für verschachtelte Strukturen oder Arrays:
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 Erstellen einer neuen Bestellung
// @Description Erstellen einer Bestellung mit mehreren Artikeln und Versandinformationen
// @Tags orders
// @Accept json
// @Produce json
// @Param order body CreateOrderRequest true "Bestelldetails"
// @Success 201 {object} Order
// @Failure 400 {object} ErrorResponse
// @Failure 422 {object} ErrorResponse
// @Security Bearer
// @Router /orders [post]
func CreateOrder(c *gin.Context) {
// Implementierung
}
Dokumentation von Datei-Uploads
// UploadImage godoc
// @Summary Hochladen eines Produktbildes
// @Description Hochladen einer Bilddatei für ein Produkt
// @Tags products
// @Accept multipart/form-data
// @Produce json
// @Param id path int true "Produkt-ID"
// @Param file formData file true "Bilddatei"
// @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")
// Upload verarbeiten
}
Abfrageparameter und Paginierung
// ListProducts godoc
// @Summary Auflisten von Produkten mit Paginierung
// @Description Abrufen einer paginierten Liste von Produkten mit optionaler Filterung
// @Tags products
// @Accept json
// @Produce json
// @Param page query int false "Seitenzahl" default(1)
// @Param page_size query int false "Elemente pro Seite" default(10)
// @Param category query string false "Filter nach Kategorie"
// @Param min_price query number false "Mindestpreis"
// @Param max_price query number false "Höchstpreis"
// @Success 200 {array} Product
// @Failure 400 {object} ErrorResponse
// @Router /products [get]
func ListProducts(c *gin.Context) {
// Implementierung mit Paginierung
}
Authentifizierung und Sicherheit
Dokumentieren Sie verschiedene Authentifizierungsmethoden in Ihrer API. Für Multi-Tenant-Anwendungen, ist eine korrekte Authentifizierungsdokumentation entscheidend:
Bearer-Token-Authentifizierung
// @securityDefinitions.apikey Bearer
// @in header
// @name Authorization
// @description Geben Sie "Bearer" gefolgt von einem Leerzeichen und JWT-Token ein.
API-Key-Authentifizierung
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
// @description API-Key für die Authentifizierung
OAuth2-Authentifizierung
// @securitydefinitions.oauth2.application OAuth2Application
// @tokenUrl https://example.com/oauth/token
// @scope.write Gewährt Schreibzugriff
// @scope.admin Gewährt Lese- und Schreibzugriff auf administrative Informationen
Basic-Authentifizierung
// @securityDefinitions.basic BasicAuth
Wenden Sie Sicherheit auf bestimmte Endpunkte an:
// @Security Bearer
// @Security ApiKeyAuth
Anpassung der Swagger-Benutzeroberfläche
Sie können das Aussehen und Verhalten der Swagger-Benutzeroberfläche anpassen:
// Benutzerdefinierte Konfiguration
url := ginSwagger.URL("http://localhost:8080/swagger/doc.json")
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
// Mit benutzerdefiniertem Titel
r.GET("/swagger/*any", ginSwagger.WrapHandler(
swaggerFiles.Handler,
ginSwagger.URL("http://localhost:8080/swagger/doc.json"),
ginSwagger.DefaultModelsExpandDepth(-1),
))
Um Swagger in der Produktion zu deaktivieren:
if os.Getenv("ENV") != "production" {
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
Integration mit CI/CD
Automatisieren Sie die Swagger-Dokumentationsgenerierung in Ihrer CI/CD-Pipeline:
# GitHub Actions Beispiel
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
Best Practices
1. Konsistenter Annotationsstil
Halten Sie eine konsistente Formatierung für alle Endpunkte aufrecht:
// HandlerName godoc
// @Summary Kurzbeschreibung (unter 50 Zeichen)
// @Description Detaillierte Beschreibung, was der Endpunkt macht
// @Tags ressourcen-name
// @Accept json
// @Produce json
// @Param name location type required "Beschreibung"
// @Success 200 {object} ResponseType
// @Failure 400 {object} ErrorResponse
// @Router /path [method]
2. Verwenden Sie beschreibende Beispiele
Fügen Sie realistische Beispiele hinzu, um API-Nutzern zu helfen:
type User struct {
ID int `json:"id" example:"1"`
Email string `json:"email" example:"benutzer@example.com"`
CreatedAt time.Time `json:"created_at" example:"2025-01-15T10:30:00Z"`
}
3. Dokumentieren Sie alle Antwortcodes
Beinhalten Sie alle möglichen HTTP-Statuscodes:
// @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. Versionieren Sie Ihre API
Verwenden Sie eine korrekte Versionierung im Basis-Pfad:
// @BasePath /api/v1
Und organisieren Sie Ihren Code entsprechend:
v1 := r.Group("/api/v1")
v2 := r.Group("/api/v2")
5. Gruppieren Sie verwandte Endpunkte
Verwenden Sie Tags, um Endpunkte logisch zu organisieren:
// @Tags products
// @Tags orders
// @Tags users
6. Halten Sie die Dokumentation aktuell
Führen Sie swag init vor jedem Commit aus oder integrieren Sie es in Ihren Build-Prozess:
#!/bin/bash
# Pre-commit Hook
swag init
git add docs/
Testen der Swagger-Dokumentation
Bei der Arbeit mit serverlosen Architekturen wie AWS Lambda wird das Testen Ihrer API-Dokumentation noch wichtiger:
func TestSwaggerGeneration(t *testing.T) {
// Überprüfen, ob swagger.json existiert
_, err := os.Stat("./docs/swagger.json")
if err != nil {
t.Fatal("swagger.json nicht gefunden, führen Sie 'swag init' aus")
}
// Überprüfen, ob der Swagger-Endpunkt antwortet
r := setupRouter()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/swagger/index.html", nil)
r.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
}
Häufige Probleme und Lösungen
Dokumentation wird nicht aktualisiert
Wenn Änderungen nicht erscheinen, stellen Sie sicher, dass Sie die Dokumente neu generieren:
swag init --parseDependency --parseInternal
Die --parseDependency-Flagge parst externe Abhängigkeiten und --parseInternal parst interne Pakete.
Benutzerdefinierte Typen werden nicht erkannt
Für Typen aus externen Paketen verwenden Sie den swaggertype-Tag:
type CustomTime struct {
time.Time
}
func (CustomTime) SwaggerDoc() map[string]string {
return map[string]string{
"time": "RFC3339-Zeitstempel",
}
}
Oder verwenden Sie den swaggertype-Tag:
type Product struct {
ID int `json:"id"`
UpdatedAt CustomTime `json:"updated_at" swaggertype:"string" format:"date-time"`
}
Arrays und Enums
Dokumentieren Sie Array-Typen und Enums:
type Filter struct {
Status []string `json:"status" enums:"active,inactive,pending"`
Tags []string `json:"tags"`
}
// @Param status query string false "Statusfilter" Enums(active, inactive, pending)
Alternative Ansätze
Während swaggo die beliebteste Wahl ist, gibt es andere Optionen:
go-swagger
Eine funktionsreichere, aber komplexere Alternative:
brew install go-swagger
swagger generate spec -o ./swagger.json
Manuelle OpenAPI-Dateien
Für vollständige Kontrolle schreiben Sie OpenAPI-Spezifikationen manuell in YAML:
openapi: 3.0.0
info:
title: Product API
version: 1.0.0
paths:
/products:
get:
summary: List products
responses:
'200':
description: Success
Dann servieren Sie mit:
r.StaticFile("/openapi.yaml", "./openapi.yaml")
Integration mit KI und LLMs
Beim Erstellen von APIs, die mit KI-Diensten integriert sind, wird eine ordnungsgemäße Dokumentation entscheidend. Zum Beispiel, wenn Sie mit strukturierten LLM-Ausgaben arbeiten, hilft Swagger bei der Dokumentation komplexer Anfrage- und Antwortschemata:
type LLMRequest struct {
Prompt string `json:"prompt" example:"Fassen Sie diesen Text zusammen"`
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
}
Leistungsüberlegungen
Swagger-Dokumentation hat minimalen Einfluss auf die Leistung:
- Build-Zeit:
swag initdauert 1-3 Sekunden für die meisten Projekte - Laufzeit: Die Dokumentation wird einmal beim Start geladen
- Speicher: Fügt typischerweise 1-2MB zur Binärdateigröße hinzu
- Antwortzeit: Kein Einfluss auf die API-Endpunkte selbst
Für sehr große APIs (100+ Endpunkte) sollten Sie in Betracht ziehen:
- Aufteilung in mehrere Swagger-Dateien
- Lazy-Loading von Swagger-UI-Assets
- Servieren der Dokumentation von einem separaten Dienst
Sicherheitsüberlegungen
Beim Freigeben von Swagger-Dokumentation:
- Deaktivieren Sie in der Produktion (wenn die API intern ist):
if os.Getenv("ENV") == "production" {
// Registrieren Sie keinen Swagger-Endpunkt
return
}
- Fügen Sie Authentifizierung hinzu:
authorized := r.Group("/swagger")
authorized.Use(AuthMiddleware())
authorized.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
- Begrenzen Sie die Rate des Endpunkts:
r.GET("/swagger/*any", RateLimitMiddleware(), ginSwagger.WrapHandler(swaggerFiles.Handler))
- Geben Sie niemals interne Details preis:
- Dokumentieren Sie keine internen Endpunkte
- Vermeiden Sie die direkte Freigabe von Datenbankschemata
- Bereinigen Sie Fehlermeldungen in der Dokumentation
Fazit
Die Hinzufügung von Swagger-Dokumentation zu Ihrer Go-API verwandelt die Entwicklererfahrung von Raten in geführte Erkundung. Die swaggo-Bibliothek macht diesen Prozess einfach, indem sie umfassende OpenAPI-Dokumentation aus Ihren Code-Anmerkungen generiert.
Wichtige Erkenntnisse:
- Beginnen Sie mit grundlegenden Anmerkungen und erweitern Sie diese schrittweise
- Halten Sie die Dokumentation durch CI/CD mit dem Code synchronisiert
- Verwenden Sie Swagger UI für interaktives Testen während der Entwicklung
- Dokumentieren Sie Authentifizierung, Fehler und Randfälle gründlich
- Berücksichtigen Sie die Sicherheitsimplikationen bei der Freigabe der Dokumentation
Ob Sie Microservices, öffentliche APIs oder interne Tools erstellen, Swagger-Dokumentation zahlt sich aus in reduzierter Supportbelastung, schnellerem Onboarding und besserer API-Gestaltung. Die anfängliche Investition in das Lernen der Annotation-Syntax wird schnell zur Routine, und die automatische Generierung stellt sicher, dass Ihre Dokumentation nie hinter Ihrer Implementierung zurückbleibt.
Für Go-Entwickler schafft die Kombination aus starkem Typing, Code-Generierung und dem Annotation-System von swaggo einen leistungsfähigen Workflow, der API-Dokumentation zu einem natürlichen Teil des Entwicklungsprozesses macht, anstatt eine Nacharbeit zu sein.
Nützliche Links
- Go Cheatsheet
- Erstellung von REST-APIs in Go
- Vergleich von Go-ORMs für PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Multi-Tenancy-Datenbankmuster mit Beispielen in Go
- LLMs mit strukturierten Ausgaben: Ollama, Qwen3 & Python oder Go
- AWS Lambda-Leistung: JavaScript vs Python vs Golang