API-Stile
Wie Programme miteinander reden: REST, gRPC, GraphQL und Ereignisse im direkten Vergleich – wie viele Anfragen dieselbe Aufgabe braucht, wer die Felder bestimmt, und warum eine Kette synchroner Aufrufe so zerbrechlich ist.
Eine API ist ein Vertrag zwischen Programmen: Welche Anfragen gibt es, was muss man mitschicken, was kommt zurück. Vier Stile prägen die Praxis. REST denkt in Ressourcen mit Adressen und benutzt HTTP so, wie es gemeint ist. gRPC denkt in Funktionsaufrufen, binär und schnell. GraphQL lässt den Client genau die Felder anfordern, die er braucht. Ereignisse drehen das Verhältnis um: Ein Dienst verkündet, was passiert ist, und andere reagieren – ohne dass der Absender auf sie wartet.
Keiner ist allgemein besser. Entscheidend sind die Fragen: Wer ruft auf – ein Browser, eine App, ein anderer Dienst? Wie eng dürfen die Beteiligten aneinander gekoppelt sein? Und was passiert, wenn einer ausfällt?
Dieselbe Aufgabe, drei Stile
Eine App will Bestellung 42 anzeigen: mit Datum, dem Namen des Kunden und den Artikelnamen der Positionen. Wie viele Anfragen braucht das?
| REST | gRPC | GraphQL | |
|---|---|---|---|
| Denkweise | Ressourcen mit Adressen | Funktionen aufrufen | einen Datengraphen abfragen |
| Transport | HTTP, meist JSON | HTTP/2, Protobuf | HTTP, ein Endpunkt, JSON |
| Vertrag | OpenAPI (optional) | .proto-Datei (Pflicht) | GraphQL-Schema (Pflicht) |
| Caching | eingebaut über HTTP | selbst lösen | schwierig: alles ist ein POST |
| Streaming | umständlich | eingebaut, in beide Richtungen | über Subscriptions |
| Im Browser | überall | nur über eine Brücke (gRPC-Web) | überall |
| Typisch für | öffentliche APIs, CRUD | interne Dienste untereinander | Frontends mit vielfältigem Datenbedarf |
REST richtig verstanden
REST ist mehr als „JSON über HTTP“. Der Kern: Alles ist eine Ressource mit eigener Adresse (/bestellungen/42), und man arbeitet mit den einheitlichen HTTP-Methoden darauf – GET liest, PUT ersetzt, DELETE löscht. Substantive in der URL, Verben in der Methode: POST /bestellungen, nicht POST /legeBestellungAn. Weil REST HTTP so benutzt, wie es gedacht ist, funktionieren Caches, Proxys, Statuscodes und Werkzeuge einfach mit.
GraphQL: Der Client bestimmt
Bei REST legt der Server fest, was eine Antwort enthält. Bei GraphQL schreibt der Client eine Abfrage mit genau den Feldern, die er braucht – und bekommt genau die zurück:
Der Preis liegt beim Server: Jede denkbare Kombination von Feldern muss effizient beantwortbar sein. Eine naive Umsetzung fragt für jede Position einzeln den Artikel ab – das N+1-Problem in neuem Gewand. Dagegen helfen „DataLoader“, die Einzelanfragen bündeln. Und weil Clients beliebig tiefe Abfragen bauen können, braucht ein öffentlicher GraphQL-Server Grenzen für Tiefe und Aufwand.
Synchron oder asynchron?
Bei REST, gRPC und GraphQL wartet der Aufrufer auf die Antwort – das ist synchron. Bei Ereignissen verkündet ein Dienst nur, was passiert ist („Bestellung 42 wurde aufgegeben“), über einen Nachrichtenvermittler. Wer sich dafür interessiert, reagiert, wann er kann. Der Unterschied zeigt sich, wenn etwas schiefgeht:
Synchrone Ketten sind leicht zu verstehen und zu debuggen, aber zerbrechlich: Ihre Verfügbarkeit ist das Produkt der Verfügbarkeiten aller Glieder, ihre Antwortzeit die Summe. Fünf Dienste mit je 99,9 % Verfügbarkeit ergeben zusammen nur noch 99,5 % – rund 44 Stunden Ausfall im Jahr statt knapp neun. Ereignisse entkoppeln: Der Absender muss die Empfänger nicht einmal kennen, und neue Empfänger kommen dazu, ohne dass er sich ändert. Der Preis ist Eventual Consistency – die Mail kommt vielleicht erst in einer Minute – und Abläufe, die schwerer nachzuvollziehen sind. Mehr dazu im Eintrag zu Messaging.
Eine leichte Form des Ereignisses über Systemgrenzen hinweg sind Webhooks: Ein externer Dienst ruft eine URL der eigenen Anwendung auf, wenn etwas passiert – etwa wenn eine Zahlung eingegangen ist. Weil jeder diese URL aufrufen könnte, prüft man eine Signatur, typischerweise einen HMAC aus der Kryptografie.
Verträge und Versionen
Eine API ist ein Versprechen an Programme, die man oft nicht kennt und nicht ändern kann. Deshalb gilt: Hinzufügen ist erlaubt, Wegnehmen und Umdeuten nicht.
| Änderung | Kompatibel? |
|---|---|
| neues optionales Feld in der Antwort | ✓ – sofern Clients unbekannte Felder ignorieren |
| neuer Endpunkt, neue Methode | ✓ |
| neues Pflichtfeld in der Anfrage | ✗ – alte Clients schicken es nicht |
| Feld umbenennen oder entfernen | ✗ – bei Protobuf ist Umbenennen harmlos, Entfernen nicht |
| Bedeutung oder Einheit ändern | ✗ – das schlimmste, weil es nicht sofort auffällt |
Die Gegenseite heißt tolerant reader: Clients sollen nur lesen, was sie brauchen, und den Rest ignorieren. Für echte Brüche gibt es Versionen – /v2/bestellungen oder ein Header –, und die alte Version läuft eine Weile parallel weiter. Bewährt hat sich, den Vertrag zuerst zu schreiben (contract first) und Code daraus zu erzeugen: aus OpenAPI, der .proto-Datei oder dem GraphQL-Schema.
Für Entwickler übersetzt
// REST mit Spring
@RestController @RequestMapping("/bestellungen")
class BestellungController {
@GetMapping("/{id}") BestellungDto lade(@PathVariable long id) { … }
@PostMapping ResponseEntity<Void> lege(@RequestBody @Valid NeueBestellung b) { … }
}
// Deklarativer HTTP-Client (seit Spring 6): ein Interface, Spring baut die Implementierung
@HttpExchange("/kunden")
interface KundenClient {
@GetExchange("/{id}") Kunde lade(@PathVariable long id);
}
// GraphQL mit Spring for GraphQL
@Controller
class BestellungGraph {
@QueryMapping Bestellung bestellung(@Argument long id) { … }
@BatchMapping Map<Bestellung, Kunde> kunde(List<Bestellung> bs) { … } // gegen N+1
}
// Ereignis veröffentlichen, z. B. mit Spring for Apache Kafka
kafka.send("bestellungen", new BestellungAufgegeben(42, kundeId, summeCent));| Werkzeug | Wofür |
|---|---|
| springdoc-openapi | erzeugt aus Spring-Controllern eine OpenAPI-Beschreibung und eine Testoberfläche |
| OpenAPI Generator | erzeugt umgekehrt aus einer OpenAPI-Datei Client- und Server-Code |
| grpc-java | erzeugt aus .proto-Dateien Stubs für Client und Server |
| Spring for GraphQL | Schema-first-GraphQL mit Annotationen, inklusive Batch-Laden |
| Problem Details | einheitliche Fehlerantworten nach RFC 9457 – in Spring über ProblemDetail |
Häufige Irrtümer
POST /getKunde benutzt HTTP, ist aber kein REST.