HÄVG RZ Dev Blog

Hier schreiben die Mitarbeiterinnen und Mitarbeiter aus dem HÄVG Rechenzentrum!

OpenAPI Dokumentation in Go

APIs in Go

Die in der Google-Werkstatt geborene Programmiersprache Go wird aufgrund ihres einfachen Aufbaus und ihrer umfangreichen Standardbibliothek im Bereich HTTP und Netzwerkaufgaben für die Entwicklung von APIs immer beliebter. Wie Daniel in seinem Artikel “Einsatz von Go im produktiven Umfeld” berichtet, haben wir auch unsere ersten Erfahrungen mit Go gesammelt, auf welche ganz viele weitere folgen sollen. Teamübergreifend überarbeiten wir große Teile unserer, in C# geschriebenen, API und versuchen die Vorteile von Go voll auszuschöpfen.

OpenAPI Spezifikation

Eine der großen Herausforderungen beim Entwickeln von APIs mit mehreren Entwicklern oder gar mit mehreren Teams, ist die enge Zusammenarbeit und der Bedarf an hochfrequenter Synchronisation. Kleinste Änderungen müssen gut dokumentiert und kommuniziert werden. Die aus diesem Schmerz entstandene weit verbreitete OpenAPI Spezifikation, auch Swagger Spezifikation genannt, wurde genau zu diesem Zweck definiert: Die Beschreibung einer API. Es können z.B. Informationen zu verfügbaren Endpunkten, Eingabe- und Ausgabeparametern oder Authentisierungsmethoden in diese Beschreibung aufgenommen werden. Da es sich bei der Entwicklung unserer API nicht nur um firmeninterne Zusammenarbeit, sondern auch um die Kooperation mit externen Partnern handelt, ist die Dokumentation der API mit der OpenAPI Spezifikation für alle Beteiligten von großem Vorteil.

OpenAPI Spezifikation in Go

Die OpenAPI Spezifikation einer API wird im vorgegebenen yaml-Format geschrieben. Für einen einzigen Endpunkt kann das wie folgt aussehen.

Beispiel: Swagger Dokumentation im yaml-Format

Beispiel: Swagger Dokumentation im yaml-Format

Quelle: https://swagger.io/docs/specification/basic-structure/

Es liegt klar auf der Hand, dass der manuelle Dokumentationsaufwand bei umfangsreicheren APIs sehr groß und mühselig werden kann. Für bekannte Programmiersprachen wie Go gibt es deshalb glücklicherweise eine solide Anzahl an code-generierenden Bibliotheken, die einem Entwickler diese Arbeit teilweise abnehmen.

Weit verbreitet sind folgende Bibliotheken und Frameworks:

Stand: 09.08.2021

In diesem Artikel schauen wir uns eine beispielhafte API an und verwenden die swaggo Bibliothek um die OpenAPI Spezifikation für uns generieren zu lassen.

Swagger Dokumentation mit swaggo

Wir betrachten eine ToDo-App, die eine Autorisierung erfordert, und in welcher ToDo-Listen mit ToDo-Punkten angelegt werden können. Der vollständige Code kann hier abgerufen werden.

Allgemeine Informationen der API

Allgemeine Informationen zur API, so wie die Bezeichnung der API, die Version, eine kurze Beschreibung, der Host und der base path können in der main.go als Kommentare folgendermaßen angegeben werden:

// @title Todo App API
// @version 1.0
// @description API Server for TodoList Application

// @host localhost:8000
// @BasePath /

// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization

Ebenso kann definiert werden, welches Authentifizierungsverfahren verwendet wird. Die Liste aller möglichen Attribute sind hier gut dokumentiert.

Beschreibung eines einzelnen Endpunkts

Weiter schauen wir uns die Dokumentation der Endpunkte am Beispiel des ToDo-Liste-erstellen-Handlers an:

// @Summary Create todo list
// @Security ApiKeyAuth
// @Tags lists
// @Description create todo list
// @ID create-list
// @Accept  json
// @Produce  json
// @Param input body todo.TodoList true "list info"
// @Success 200 {integer} integer 1
// @Failure 400,404 {object} errorResponse
// @Failure 500 {object} errorResponse
// @Failure default {object} errorResponse
// @Router /api/lists [post]
func (h *Handler) createList(c *gin.Context) {
	userId, err := getUserId(c)
	if err != nil {
		newErrorResponse(c, http.StatusInternalServerError, err.Error())
		return
	}

	var input todo.TodoList
	if err := c.BindJSON(&input); err != nil {
		newErrorResponse(c, http.StatusBadRequest, err.Error())
		return
	}

	id, err := h.services.TodoList.Create(userId, input)
	if err != nil {
		newErrorResponse(c, http.StatusInternalServerError, err.Error())
		return
	}

	c.JSON(http.StatusOK, map[string]interface{}{
		"id": id,
	})
}

Wichtig ist hier zunächst anzumerken, dass die Kommentare jetzt direkt über dem Handler (ohne Leerzeile) stehen müssen, damit die Bibliothek den yaml-Code für den Handler generieren kann.

Für die Dokumentation der Endpunkte gibt es ebenfalls eine Reihe an vorgegebenen Attributen (vollständige Liste siehe hier). Zu dem gegebenen Beispiel hier ein paar kleine Erläuterungen:

  • Mit dem Tag Security kann festgelegt werden, welche Authentifizierung für diesen Endpunkt notwendig ist.
  • Mit Tags können die Endpunkte in Gruppen eingeteilt werden, beispielsweise nach dem Teilpfad gruppiert.
  • Die Tags Accept und Produce geben an, welchen MIME-Typen der Endpunkt erwartet und welchen er zurückgibt. Die zu verwendenden Aliase sind hier dokumentiert.
  • Mit dem Tag Param werden Informationen zu Parametern angegeben, indem einfach, durch Leerzeichen getrennt, der Name, der Parametertyp, der Datentyp, ein Verpflichtend-Flag(true/false) und ein Kommentar aufgelistet werden.
  • Der Response kann mit dem Tag Response oder aufgesplittet in die Tags Success und Failure beschrieben werden. Dazu werden ähnlich wie bei den Parametern, die Eigenschaften Statuscode, Parametertype in geschweiften Klammern, der Datentyp und der Kommentar mit Leerzeichen dazwischen aufgereiht.
  • Zuletzt sehen wir in dem oben aufgeführten Beispiel noch den Tag Router, über welchen der Pfad und die zugehörige http-Methode in eckigen Klammern dokumentiert werden können.

Swagger-Dokumentation generieren

Um nun die zugehörigen Dateien für die API zu generieren, muss die Bibliothek installiert sein. Dazu kann einfach der go get -u github.com/swaggo/swag/cmd/swag-Befehl ausgeführt werden. Navigiert man in das Wurzelverzeichnis des Go-Projekts und ruft swag init auf, so werden die Swagger-Dateien generiert und im docs-Ordner abgelegt. Sind die allgemeinen API-Informationen in einer anderen Datei als der main.go enthalten, so kann mit einem zusätzlichen Flag swag init -g todo-app/api.go die Datei angegeben werden.

Swagger-Dokumentation anzeigen

Zum Anzeigen der yaml-Dateien kann nun in VS Code die Swagger Viewer Extension verwendet werden oder die yaml-Datei beispielsweise http-abrufbar gemacht werden. Ebenfalls bietet es sich an, die Dokumentation in Swagger Editor auszutesten. Für unsere ToDo-List-API sieht die Swagger Dokumentation wie folgt so aus.

Beispiel: API-Dokumentation in Swagger-Format

Beispiel: API-Dokumentation in Swagger-Format

Zusammenfassung

Die Dokumentation einer API im Swagger-Format ist sowohl für die Entwickler als auch für die Consumer der API von großem Nutzen. Code-generierende Bibliotheken für Go sind einfach zu verwenden und unterstützen bei der regelmäßigen Dokumentation und erleichtern somit den Prozess.