API in Go: REST, GraphQL und gRPC – was wählt man 2025

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Warum Go die ideale Sprache für APIs ist?

\n\n

Wenn es um die Erstellung hochlastiger APIs geht, belegt Go (Golang) souverän einen Spitzenplatz. Seine kompilierte Natur, die integrierte Unterstützung für Nebenläufigkeit durch Goroutinen und die minimalistische Syntax ermöglichen das Schreiben schneller und zuverlässiger Microservices. Aber welches Protokoll sollten Sie für Ihr nächstes Projekt wählen: das klassische REST, das flexible GraphQL oder das extrem schnelle gRPC?

\n\n

In diesem Artikel werden wir nicht nur die Unterschiede auflisten – wir werden echten Code in Go für jeden Ansatz schreiben, Benchmarks analysieren und klare Auswahlkriterien nennen. Los geht's!

\n\n

REST API in Go: Bewährte Klassik

\n\n

REST (Representational State Transfer) bleibt der De-facto-Standard für öffentliche APIs. Go bietet eine hervorragende Standardbibliothek net/http sowie beliebte Frameworks wie gin und echo.

\n\n

Beispiel eines REST-Servers in reinem Go

\n\n

Beginnen wir mit einem einfachen CRUD-Dienst zur Aufgabenverwaltung. So sieht eine minimale REST-API in Go ohne externe Abhängigkeiten aus:

\n\n
package main\n\nimport (\n    "encoding/json"\n    "log"\n    "net/http"\n    "sync"\n)\n\ntype Task struct {\n    ID   int    `json:"id"`\n    Name string `json:"name"`\n}\n\nvar (\n    tasks   = []Task{{ID: 1, Name: "Go lernen"}}\n    mu      sync.Mutex\n    nextID  = 2\n)\n\nfunc getTasks(w http.ResponseWriter, r *http.Request) {\n    mu.Lock()\n    defer mu.Unlock()\n    w.Header().Set("Content-Type", "application/json")\n    json.NewEncoder(w).Encode(tasks)\n}\n\nfunc createTask(w http.ResponseWriter, r *http.Request) {\n    var task Task\n    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {\n        http.Error(w, err.Error(), http.StatusBadRequest)\n        return\n    }\n    mu.Lock()\n    task.ID = nextID\n    nextID++\n    tasks = append(tasks, task)\n    mu.Unlock()\n    w.WriteHeader(http.StatusCreated)\n    json.NewEncoder(w).Encode(task)\n}\n\nfunc main() {\n    http.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {\n        switch r.Method {\n        case http.MethodGet:\n            getTasks(w, r)\n        case http.MethodPost:\n            createTask(w, r)\n        default:\n            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)\n        }\n    })\n    log.Println("REST API gestartet auf :8080")\n    log.Fatal(http.ListenAndServe(":8080", nil))\n}\n
\n\n

Vorteile von REST in Go:

\n
    \n
  • Einfachheit und Vorhersagbarkeit – jeder Endpunkt gibt eine feste Datenstruktur zurück
  • \n
  • Hervorragende Caching-Fähigkeit über HTTP-Header
  • \n
  • Breite Unterstützung durch Tools (Swagger, Postman)
  • \n
\n\n

Nachteile: Over-fetching und Under-fetching von Daten. Wenn der Client nur den Namen einer Aufgabe benötigt, erhält er trotzdem das vollständige JSON.

\n\n

GraphQL in Go: Flexibilität bei Abfragen

\n\n

GraphQL löst das Problem der Datenredundanz. Der Client entscheidet selbst, welche Felder er benötigt. Die Go-Community bietet die leistungsstarke Bibliothek gqlgen, die Code aus dem Schema generiert.

\n\n

Beispiel eines GraphQL-Servers mit gqlgen

\n\n

Zuerst definieren wir das Schema schema.graphql:

\n\n
type Task {\n    id: ID!\n    name: String!\n}\n\ntype Query {\n    tasks: [Task!]!\n}\n\ntype Mutation {\n    createTask(name: String!): Task!\n}\n
\n\n

Jetzt starten wir die Generierung und schreiben die Resolver in Go:

\n\n
package main\n\nimport (\n    "log"\n    "net/http"\n    "github.com/99designs/gqlgen/graphql/handler"\n    "github.com/99designs/gqlgen/graphql/playground"\n)\n\n// Wir gehen davon aus, dass der generierte Code bereits vorhanden ist\ntype Resolver struct {\n    tasks []Task\n    mu    sync.Mutex\n}\n\nfunc (r *Resolver) Tasks(ctx context.Context) ([]Task, error) {\n    r.mu.Lock()\n    defer r.mu.Unlock()\n    return r.tasks, nil\n}\n\nfunc (r *Resolver) CreateTask(ctx context.Context, name string) (*Task, error) {\n    r.mu.Lock()\n    defer r.mu.Unlock()\n                

Blogs

Buchempfehlungen