© S&S Media, © https://blog.golang.org/gopher, © Renee French
Entspannte Schnittstellen für Gopher

RESTful APIs in Go


Alle bauen APIs. Grob geschätzt bestehen 80 Prozent der heute entwickelten Anwendungen im Kern aus einer oder mehreren serverseitigen Komponenten, die Geschäftslogik kapseln und diese ihren Clients über ein RESTful API zur Verfügung stellen. Ist das REST-Paradigma einmal verstanden, dann sind REST-APIs klar und einfach zu benutzen.

Video: Should I stay or should I "Go"

Go ist eine einfache, statisch typisierte, kompilierte und performante Programmiersprache, die sich hervorragend für die Entwicklung von REST-APIs eignet. Eigenschaften wie leichte Erlernbarkeit, ein simples und leistungsfähiges Concurrency-Modell, sehr guter HTTP-, REST- und JSON-Support, Cross-Plattform-Fähigkeit sowie einfaches Deployment zeichnen Go aus. Dieser Beitrag führt in die wesentlichen Aspekte der REST-Entwicklung in Go anhand eines einfachen Beispiels ein. Der Artikel verzichtet dabei auf eine explizite Einführung der Programmiersprache Go. Stattdessen werden Go-spezifische Konzepte erklärt, wenn sie im Kontext des Beispiels zum Einsatz kommen.

REST am fachlichen Beispiel

Den fachlichen Hintergrund des Beispiel-API bildet ein einfaches Shopsystem. Das Domainmodell des Shops besteht aus den Entitäten Customer, Order und Product. Abbildung 1 zeigt deren Beziehungen, URIs sowie JSON-Repräsentationen.

wirdemann_go_1.tif_fmt1.jpgAbb. 1: Shop als fachliches Beispiel

Eine Ressource im REST-Kontext ist eine Abstraktion, die ein „Ding“ referenziert. Dieses Ding kann z. B. ein einzelner Kunde, eine Liste aller Kunden oder auch eine Liste von Kunden mit dem Namen Meyer sein. Ressourcen werden über URIs identifiziert. So identifiziert der URI /customers die Liste aller Kunden und die Ressource /customer/1 den Kunden mit der ID 1. Neben einer Identität besitzen Ressourcen eine oder mehrere Repräsentationen. Im Beispiel werden Ressourcen in JSON repräsentiert und in diesem Format zwischen Client und Server übertragen.

Beziehungen zwischen Ressourcen werden über Links beschrieben. Für HTML-repräsentierte Ressourcen wird häufig das HTML-Element <link> genutzt, während in JSON-Repräsentationen verlinkte Ressourcen als Listen von IDs beschrieben werden.

Das Anfragen, Anlegen, Verändern und Löschen von Ressourcen erfolgt über die HTTP-Methoden GET, POST, PUT und DELETE, im REST-Kontext auch als HTTP-Verben bezeichnet. So liefert GET /customers/1/orders/9 die Bestellung mit der ID 9, während DELETE /customers/1/orders/9 diese Bestellung löscht.

Das Shopbeispiel ist relativ einfach gehalten und kann entgegen gängigen Trends durchaus als monolithisches API entwickelt werden. Aus didaktischen Gründen entscheiden wir uns dennoch für eine Microservices-Architektur, sodass wir den Artikelfokus leichter auf den Catalog-Teil des API legen können.

wirdemann_go_2.tif_fmt1.jpgAbb. 2: Microservices-Architektur des Shopsystems

Hello net/http

Dreh- und Angelpunkt der REST-Programmierung in Go ist das Package net/http. Ein einfacher HTTP-Server ist schnell programmiert und folgt dem Schema aus Listing 1.

Listing 1

func main() { http.HandleFunc("/catalog/products", productsHandler) http.ListenAndServe(":8080", nil) } func productsHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Schuhe, Hose, Hemd")) }

Jedes Go-Programm besitzt eine Funktion main, die beim Programmstart aufgerufen wird. Die Funktion main registriert die Funktion productsHandler als Handler für HTTP Requests auf den URI /catalog/products. Der HTTP-Server blockiert im Aufruf http.ListenAndServe und nimmt auf Port 8080 Requests entgegen. Eingehende Requests werden an die Funktion productsHandler delegiert, die ihre Antwort durch den Aufruf der Methode Write in die HTTP Response schreibt. Für jeden Request startet die Go Runtime eine Go-Routine, die den Request im Hintergrund auf einem eigenen Thread abwickelt.

Ressourcen, Domainobjekte und ihre JSON-Repräsentation

Ressourcen werden API-intern als Domainobjekte repräsentiert. Domainobjekte werden in Go als Structs modelliert. Ein Struct ist ein zusammengesetzter Typ, der aus einer Reihe von Attributen besteht. In ihrer einfachsten Form bestehen Produkte aus einer ID und einem Namen:

type Product struct { Id int Name string }

Die von dem URI /catalog/products/11 referenzierte Ressource wird als Domainobjekt vom Typ Product verwaltet. Für jeden Struct-Typ stellt der Go-Compiler ein Literal zur Erzeugung von Instanzen dieses Typs zur Verfügung. Ähnlich einem Konstruktoraufruf werden dem Typnamen die Initialisierungswerte der Attribute in geschweiften Klammern übergeben. Die Angabe der Attributnamen ist optional, sofern das Struct vollständig und die Attribute in der definierten Reihenfolge initialisiert werden:

p := catalog.Product{Id: 11, Name: "Schuhe"}

Um Ressourcen zwischen API und Client auszutauschen, müssen sie repräsentiert werden. Neben HTML und XML ist JSON eines der gängigsten Repräsentationsformate im Kontext von REST. Go enthält im Package encoding/json der Standardbibliothek bereits alle notwendigen Funktionen für das JSON Marshalling und Unmarshalling von Domainobjekten. Listing 2 erweitert die Funktion productsHandler so, dass die Produkte als serialisierter JSON-String an den Client geliefert werden. Die dabei verwendete Funktion json.Marshal entstammt dem importierten Package encoding/json, das diese Funktion exportiert. Die von einem Package exportierten Funktionen sind dadurch gekennzeichnet, dass sie großgeschrieben sind.

Listing 2

import "encoding/json" func productsHandler(w http.ResponseWriter, r *http.Request) { p := catalog.Product{Id: 11, Name: "Schuhe"} products := []catalog.Product{p} json, _ := json.Marshal(products) w.Write(json) }

Der Produktkatalog wird im Beispiel als Array mit einem einzelnen Produkt repräsentiert. Die Funktio...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang