Warum Go die ideale Sprache für APIs ist?
\n\nWenn 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\nIn 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\nREST API in Go: Bewährte Klassik
\n\nREST (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.
Beispiel eines REST-Servers in reinem Go
\n\nBeginnen wir mit einem einfachen CRUD-Dienst zur Aufgabenverwaltung. So sieht eine minimale REST-API in Go ohne externe Abhängigkeiten aus:
\n\npackage 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\nVorteile 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
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\nGraphQL in Go: Flexibilität bei Abfragen
\n\nGraphQL 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.
Beispiel eines GraphQL-Servers mit gqlgen
\n\nZuerst definieren wir das Schema schema.graphql:
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\nJetzt starten wir die Generierung und schreiben die Resolver in Go:
\n\npackage 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