undefined brand logo

Von Express zu Go – mein Weg zu minimalistischen HTTP‑APIs

Von Markus
Backend Development
10.06.2025
Go HTTP API Development Tutorial - Building APIs without External Dependencies

Vorab: Der gesamte Code über den ich spreche ist hier veröffentlicht: https://github.com/trakora/production-go-api-template

Pull Requests und Issues sind willkommen.

Der Ausgangspunkt

Ich kam aus der JavaScript‑Welt. Wenn ich eine API brauchte, tippte ich:

npm install express
node index.js

Schnell gemockt, schnell deployed. Für jedes Problem gab es eine schöne fertige Libary, die alles übernahm. Das ging so lange gut, bis ich irgendwann keinen Schimmer mehr davon hatte, was eigentlich im Hintergrund ablief.

JS (und, ja, auch TypeScript) verführt einen zur schnellen Lösung und zu schlampigem Code, bei mir jedenfalls. Viele meiner Projekte haben keine 10 Entwickler und Architekten.

Mir war klar: Ich brauche einen Perspektivwechsel.

Ich hatte die Wahl zwischen Go und Rust. Da jedoch Rust eine sehr viel höhere Lernkurve hatte, war Go die Wahl. Ob ich damit hundertprozentig glücklich bin? Keine Ahnung. Aber eins kann ich sagen: Es macht mir deutlich mehr Spaß als das alte Node-Gewusel.

Erste Begegnung mit Go HTTP

Als ich loslegte, gab es in der Standard-Lib praktisch nichts Komfortables. Mit der Version Go 1.22 konnte ich dann so richtig starten.

Nach „Hello, world“ stolperte ich aber über Begriffe wie ServeMux und HandlerFunc. In Node hatte ich app.get("/posts/:id").

In Go musste ich mir das so hinbasteln:

mux := http.NewServeMux()
mux.HandleFunc("/posts/", postHandler)

Alle Artikel, die ich las, nutzten Libraries wie chi odergorilla/mux. Ich wollte aber diesmal wissen, wie weit ich allein mit der Standardbibliothek komme und mich nicht dauerhaft auf externe Projekte verlassen.

Drei Artikel, die mir weitergeholfen haben

Ich habe die drei Artikel gefunden, die bei mir die Grundlage für den Einstieg geboten haben.

Alle drei sagen im Kern: mach erst mal alles mit net/http, bevor du nach einer Library greifst.

Mein Minimal‑Prototyp

package main

import (
	"log"
	"net/http"
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("pong"))
	})

	log.Println("listening on :8080")
	log.Fatal(http.ListenAndServe(":8080", mux))
}

Kein Routing‑Framework, kein JSON‑Helper. Das Ding läuft, und ich verstehe jede Zeile. Durch den Artikel Backend Basics konnte ich auch zum ersten Mal tief eintauchen und die Funktionsweise von HandleFunc nachvollziehen.

Der Code der Standardbibliothek ist hervorragend geschrieben und vermittelt direkt, was passiert.

Vom Prototyp zum Template‑Repo

Mehr Endpunkte → mehr Chaos.

Als mehr Endpunkte dazukamen, brauchte ich Struktur: Config, Logging, Middleware.
Daraus entstand das Production‑Go‑API‑Template. Ordner wie /cmd, /api, /pkg und eine saubere Trennung in Handler → Service → Repository.

Warum ich so wenig Libraries einsetze

Wenn ich auf externe Libraries verzichte, gewinne ich drei Dinge – und zwar spürbar:

Kontrolle

Ich kenne jede Zeile, die auf meinem Server läuft. Keine Magie, keine versteckten Side-Effects. Tritt ein Bug auf, kann ich ihn nachverfolgen, statt erst einmal den Issues-Tab eines GitHub-Projekts zu durchforsten.

Weniger Upgrades

Bei npm install verstehe ich nicht einmal die tausend Upgrades, die ich täglich durchführen müsste. Nodejs Meme

Meine Build-Pipeline bleibt schlank, und ich muss nicht alle paar Wochen prüfen, ob Version 3.4.2 eines Frameworks wieder einen Breaking Change mit sich bringt.

Besseres Lernen

Wer sich auf die Standardbibliothek einlässt, bekommt Go quasi im Quelltext erklärt. Jeder Handler, jedes Interface steht schwarz auf weiß vor mir. Das zwingt zum Begreifen – und sorgt dafür, dass ich später tatsächlich beurteilen kann, wann sich eine zusätzliche Library lohnt und wann nicht.

Kurz: Weniger Plug-and-Play, mehr Durchblick. Und genau das macht am Ende den Code robuster und mich als Entwickler ein Stück souveräner.

Fazit

Express war gemütlich, aber Go zwingt mich, bewusst zu entscheiden: Welche Abhängigkeit ist wirklich nötig? Die Standardbibliothek deckt locker 80 Prozent ab. Für den Rest wähle ich Libraries gezielt aus. Mein Template‑Repo wächst organisch, ohne dass ich alle paar Wochen ein Framework upgraden muss. Ich bin glücklich mit der Entscheidung und werde diese Doktrin künftig auch bei anderen Projekten anwenden.