Swagger-UI mit OpenAPI Specification 3.1 in Go
![](https://blog.enricopau.de/img/thumbnails/oas31.jpg)
| Foto von Elena Rouame auf Unsplash
Swagger-UI für OpenAPI Specification 3.1 mit Golang hosten
Vorab: ein großes Lob gilt Mario Carrion, der die Grundlagen dieser Anleitung in seinem Blogpost beschrieben hat. Ein paar Dinge haben sich seit 2021 geändert, aber der Prozess ist grundlegend derselbe. Wem das Problem bekannt ist, kann auch gerne direkt zur Anleitung springen.
Was ist OpenAPI Specification?
Ehemalig unter dem Namen ‘Swagger’ bekannt, ist die OpenAPI Specification ein offener Standard, um HTTP Schnittstellen (APIs) zu beschreiben. Die Spezifikation wird seit 2015 von der OpenAPI Initiative verwaltet.
Das Problem
Die OpenAPI Spezifikation ist quelloffen und programmiersprachenagnostisch, was dazu führt, dass es viele Tools, Packages, Libraries, etc. gibt um mit der Spezifikation zu arbeiten.
Eines dieser Tools ist swaggo, ein Golang-Projekt, welches es sich zum Ziel gesetzt hat, aus Go Quellcode automatisch REST-API-Dokumentationen mit der OpenAPI Spezifikation zu erstellen.
Dabei unterstützt swaggo viele beliebte Go-Router Implementationen, wie zum Beispiel gin, echo, gorilla/mux oder auch das zur Go-Standardbibliothek gehörende net/http-package, um automatisch eine Swagger-UI zur Verfügung zu stellen.
Aber leider ist es aktuell mit swaggo nicht möglich eine OAS 3.1 kompatible Swagger-UI zu hosten.
Auch andere Alternative OSS Go-Tools tun sich schwer, up-to-date mit dem neuestens Standard zu sein.
Macht aber nichts, denn das können wir auch selbst in die Hand nehmen.
Anleitung
Einen kleinen Server aufsetzen
Als allererstes brauchen wir einen kleinen funktionsfähigen Server, welcher dank gorilla/mux schnell aufgesetzt ist:
go get -u github.com/gorilla/mux
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/success", getSuccess).Methods(http.MethodGet)
_ = http.ListenAndServe(":8003", r)
}
func getSuccess(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "success")
}
OpenAPI Spezifikation generieren
Dankenswerterweise können wir swaggo trotz der anfangs beschriebenen Probleme nutzen! Denn das Tool (swaggo/swag) der Spezifikation unterstützt seit seiner v2.0.0-beta das Generieren von OpenAPI Spezifikationen der Version 3.1.
⚠️ Achtung: Wir arbeiten ab jetzt mit einem RC (Release Candidate), der Fehler haben kann!
Da es noch keinen offiziellen Release gibt, müssen wir uns hier ein wenig selbst helfen: Quellcode aus dem Release v2.0.0-rc3 herunterladen, entpacken, öffnen und eine ausführbare Binärdatei bauen mit dem Befehl go build -o swag.exe .\cmd\swag\main.go
.
Linux:
go build -o swag.bin ./cmd/swag/main.go
macOS:go build -o swag.app ./cmd/swag/main.go
Danach können wir das gebaute Tool swag.exe
neben unseren Server legen oder zum Pfad hinzufügen.
Bevor wir unsere Spezifikation generieren lassen können, müssen wir unseren Quellcode noch mit sinnvollen ‘Kommentaren’ versehen, die vom Generator gelesen werden können. Da dies hier keine OpenAPI-Anleitung ist, beschränken wir uns auf das Mindeste:
// @title OpenAPI 3.1 Example
// @version 1.0
func main() {
r := mux.NewRouter()
r.HandleFunc("/success", GetSuccess).Methods(http.MethodGet)
_ = http.ListenAndServe(":8003", r)
}
func GetSuccess(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "success")
}
Die Spezifikation generieren wir dann mit .\swag.exe init --v3.1
.
Dies legt uns einen Ordner ./docs/
an, indem wir unsere swagger.json und swagger.yaml finden. Einmal kurz die go.mod
aktualisieren: go mod tidy
- und unser Code sollte wieder fehlerfrei sein.
Swagger-UI statisch hosten
Damit wir die Swagger-Spezifikations visuell wiedergeben können, brauchen wir Swagger-UI.
Eine UI-Distribution können wir uns via auf Github herunterladen.
Den Ordnerinhalt dist
legen wir nun neben unseren Router in einen beliebig genannten Ordner (in unserem Fall swaggerui
).
Als nächstes binden wir die Dateien über Embedding ein
//go:embed swaggerui
var Swaggerui embed.FS
und hosten das Dateisystem unter dem Pfad “/swaggerui/” über unseren Server:
// @title OpenAPI 3.1 Example
// @version 1.0
func main() {
r := mux.NewRouter()
r.HandleFunc("/success", GetSuccess).Methods(http.MethodGet)
fsys, _ := fs.Sub(Swaggerui, "swaggerui")
r.PathPrefix("/swaggerui/").Handler(http.StripPrefix("/swaggerui/", http.FileServer(http.FS(fsys))))
_ = http.ListenAndServe(":8003", r)
}
Eigene Spezifikation einfügen
Zuletzt müssen wir noch unsere eigene generierte Spezifikation bereitstellen.
Das machen wir, indem wir die Datei swagger.json
aus dem Ordner /docs/
in den Ordner /swaggerui/
kopieren und in der Datei swagger-initialize.js
, die den Wert der url
ändern, der aktuell auf “https://petstore.swagger.io/v2/swagger.json” zeigt:
url: "./swagger.json",
Testen
Jetzt können wir den Server mit go run main.go
laufen lassen und über unseren Webbrowser “https://localhost:8003/swaggerui/index.html” die Swagger-UI aufrufen.
Das ganze Codebeispiel
package main
import (
"embed"
"fmt"
"io/fs"
"net/http"
"github.com/gorilla/mux"
)
//go:embed swaggerui
var swaggerui embed.FS
// @title OpenAPI 3.1 Example
// @version 1.0
func main() {
r := mux.NewRouter()
r.HandleFunc("/success", GetSuccess).Methods(http.MethodGet)
fsys, _ := fs.Sub(swaggerui, "swaggerui")
r.PathPrefix("/swaggerui/").Handler(http.StripPrefix("/swaggerui/", http.FileServer(http.FS(fsys))))
_ = http.ListenAndServe(":8003", r)
}
func GetSuccess(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "success")
}