- In der Softwareentwicklung sind APIs ein zentrales Werkzeug, und eine gute API sollte so vertraut und einfach sein, dass sie schon fast langweilig wirkt
- Da sich eine API nach ihrer Veröffentlichung nur schwer ändern lässt, ist das Prinzip die Umgebung der Nutzer nicht zu zerstören (WE DO NOT BREAK USERSPACE) von zentraler Bedeutung
- Wenn Änderungen unvermeidbar sind, ist Versionierung (versioning) nötig, aber sie ist ein notwendiges Übel, das Komplexität und Wartungskosten stark erhöht
- Die Qualität einer API hängt letztlich vom Wert des Produkts selbst ab; ein schlecht konzipiertes Produkt macht es schwer, eine gute API zu bauen
- Für Stabilität und Skalierbarkeit sollten API-Key-basierte Authentifizierung, Idempotenz, Rate Limits und cursorbasierte Pagination berücksichtigt werden
Einleitung: Bedeutung und Kontext von API-Design
- Eine der wichtigsten Aufgaben moderner Softwareingenieure ist die Interaktion mit APIs
- Der Autor hat selbst Erfahrung im Entwurf, in der Implementierung und in der Nutzung verschiedenster öffentlicher und interner APIs gesammelt, darunter REST, GraphQL und Kommandozeilen-Tools
- Bestehende Ratschläge zu API-Design neigen oft dazu, sich an komplexen Konzepten festzubeißen (Definitionen von REST, HATEOAS usw.)
- Dieser Text fasst auf Basis praktischer Erfahrung pragmatische Prinzipien für API-Design zusammen
Das Gleichgewicht zwischen Vertrautheit und Flexibilität: die erste Voraussetzung für eine gute API
- Eine gute API ist eine „gewöhnliche und langweilige“ API, also eine, deren Nutzung bestehenden APIs ähnelt, die man bereits kennt
- Nutzer wollen sich nicht auf die API selbst, sondern auf das Erreichen ihres Ziels konzentrieren, daher braucht es ein Design mit niedriger Einstiegshürde
- Eine einmal veröffentlichte API lässt sich nur sehr schwer ändern, weshalb schon in der ersten Entwurfsphase große Sorgfalt nötig ist
- Entwickler wünschen sich eine möglichst schlanke API, müssen aber zugleich immer mitdenken, wie sie langfristige Flexibilität erhalten
- Entscheidend ist daher letztlich die Balance zwischen Vertrautheit und langfristiger Flexibilität
User Space niemals kaputtmachen (WE DO NOT BREAK USERSPACE)
- Änderungen wie das Hinzufügen neuer Felder zu einer bestehenden Antwortstruktur sind in den meisten Fällen unproblematisch
- Das Entfernen von Feldern oder das Ändern von Typen bzw. Strukturen führt jedoch dazu, dass der Code aller Konsumenten bricht
- API-Verantwortliche haben die Verantwortung, die Software bestehender Nutzer nicht absichtlich unbrauchbar zu machen
- Selbst der Tippfehler im HTTP-Header „referer“ wird nicht korrigiert, weil es eine Kultur gibt, User Space zu bewahren
APIs ändern, ohne sie zu brechen: Strategien zur Versionierung
- Breaking Changes sollten nur dann zugelassen werden, wenn sie absolut unvermeidbar sind; dann ist Versionierung die richtige Antwort
- Alte und neue Versionen sollten parallel betrieben werden, um einen schrittweisen Übergang zu ermöglichen
- Versionskennungen können auf verschiedene Weise eingebunden werden, etwa über die URL (
/v1/) oder Header, sodass Nutzer in ihrem eigenen Tempo migrieren können
- Versionierung bringt erhebliche Nachteile mit sich: enorme Wartungskosten (mehr Endpunkte, Tests, Support) und Verwirrung bei Nutzern
- Selbst wenn man wie Stripe eine interne Übersetzungsschicht einzieht, lässt sich die grundlegende Komplexität nicht vermeiden
- Die Einführung von API-Versionierung sollte das letzte Mittel sein
Der Erfolg einer API hängt vollständig vom Wert des Produkts ab
- Eine API ist im Kern nichts anderes als die Schnittstelle zu einem realen Geschäftsprodukt
- Bei APIs wie OpenAI oder Twilio wollten Nutzer letztlich genau die Funktionalität, die diese APIs bereitstellen
- Ein wertvolles Produkt wird auch dann genutzt, wenn seine API unbequem ist
- API-Qualität ist eher eine Eigenschaft am Rand: Sie wird vor allem dann zum Entscheidungskriterium, wenn die eigentliche Wettbewerbsfähigkeit ähnlich ist
- Umgekehrt ist ein Produkt ohne API für technische Nutzer ein großes Hindernis
Wenn das Produktdesign schlecht ist, kann auch die API nicht gut werden
- Selbst eine technisch sehr ausgereifte API ist bedeutungslos, wenn das Produkt keinen Marktwert hat
- Noch wichtiger: Wenn die grundlegende Ressourcenstruktur unlogisch oder ineffizient ist, zeigt sich das auch in der API
- Ein System, das Kommentare etwa als Linked List speichert, erschwert schon von Grund auf ein natürliches RESTful Design
- Technische Probleme, die sich in einer UI verstecken lassen, werden in einer API vollständig sichtbar und zwingen Nutzern unnötig ein tieferes Systemverständnis auf
Authentifizierung (Authenticaton) und die Vielfalt der Nutzer
- API-Key-basierte Authentifizierung mit langer Lebensdauer sollte unbedingt unterstützt werden
- Auch wenn zusätzlich sicherere Verfahren wie OAuth unterstützt werden, ist die Einstiegshürde bei API-Keys deutlich niedriger
- Zu den API-Konsumenten gehören nicht nur Ingenieure, sondern auch Nicht-Entwickler wie Vertrieb, Planung, Studierende oder Hobbyentwickler
- Schwierige oder komplexe Authentifizierungsanforderungen (wie OAuth) sind für nicht spezialisierte Nutzer eine Hürde
Idempotenz und Retry-Verarbeitung
- Bei aktionsbezogenen Requests (z. B. Zahlungen oder Statusänderungen) ist die Sicherheit bei Retries im Fehlerfall entscheidend
- Idempotenz bedeutet, dass dieselbe Anfrage mehrfach gesendet werden kann, das Ergebnis aber nur einmal verarbeitet wird
- Der Standardansatz ist, einen Idempotency Key als Parameter oder Header mitzugeben, um doppelte Verarbeitung zu verhindern
- Zum Speichern von Idempotency Keys reicht ein einfacher Key-Value-Store wie Redis aus; in den meisten Fällen ist auch ein periodisches Verfallenlassen unproblematisch
- Für Lese- oder Löschanfragen (im REST-Stil) ist das in der Regel nicht nötig
API-Sicherheit und Rate Limiting
- API-Anfragen per Code können in viel höherer Geschwindigkeit auftreten als durch manuelle Benutzerinteraktion
- Eine unbedacht veröffentlichte API kann auf unerwartete Weise genutzt werden, etwa für ein groß angelegtes Chat-System
- Rate Limiting ist zwingend erforderlich und sollte bei rechenintensiven Operationen strenger ausfallen
- Auch eine temporäre Deaktivierung der API für bestimmte Kunden (Killswitch) sollte als Option erwogen werden
- Über Response-Header wie
X-Limit-Remaining und Retry-After sollten Informationen zum Rate Limit kommuniziert werden
Pagination-Strategien
- Um große Datensätze (z. B. Millionen von Tickets) effizient zurückzugeben, ist Pagination unverzichtbar
- Offset-basierte Pagination ist einfach, wird bei großen Datenmengen jedoch zunehmend langsamer
- Cursorbasierte Pagination funktioniert auch bei sehr großen Datensätzen effektiv, ohne dass die Query-Performance einbricht
- Sie ist in Implementierung und Nutzung etwas schwieriger, dürfte langfristig aber eine unvermeidliche Entwicklung sein
- Es ist sinnvoll, in die Antwort ein Feld wie
next_page aufzunehmen, um den Cursor für die nächste Anfrage klar anzugeben
Optionale Felder und die Sicht auf GraphQL
- Teure oder langsame Felder sollten in der Standardantwort weggelassen und nur bei Bedarf selektiv ergänzt werden
- Mit Parametern wie
includes können verknüpfte Daten eingebunden werden
- GraphQL bietet Vorteile bei der Flexibilität der Datenstruktur, bringt aber auch Probleme mit sich, etwa geringere Zugänglichkeit für Nicht-Entwickler, komplizierteres Caching und mehr Edge Cases sowie höhere Komplexität im Backend
- Nach praktischer Erfahrung sollte GraphQL nur dann eingeführt werden, wenn es wirklich nötig ist
Besonderheiten interner APIs
- Interne APIs unterscheiden sich in vielerlei Hinsicht von externen bzw. öffentlich bereitgestellten APIs
- Da die Konsumenten meist professionelle Softwareingenieure sind, sind komplexere Authentifizierung oder auch Breaking Changes eher möglich
- Dennoch bleiben Designprinzipien wie Idempotenz, Unfallvermeidung und die Minimierung des Betriebsaufwands gültig
Zusammenfassung
- APIs lassen sich nur schwer ändern und sollten leicht zu benutzen sein
- User Space nicht kaputtzumachen ist die wichtigste Pflicht von API-Verantwortlichen
- API-Versionierung sollte wegen ihrer hohen Kosten nur als letztes Mittel eingesetzt werden
- Letztlich wird die Qualität einer API vom eigentlichen Wert des Produkts bestimmt
- Ein schlecht entworfenes Produkt lässt sich auf API-Ebene nur begrenzt kompensieren
- Wichtig sind die Unterstützung einfacher Authentifizierung, für kritische aktionsbezogene Requests unbedingt Idempotenz, sowie Stabilitätsmaßnahmen wie Rate Limiting und Pagination
- Interne APIs erfordern je nach Zweck und Zielgruppe andere Strategien, dennoch bleibt sorgfältiges Design unverzichtbar
- Formate wie REST, JSON oder OpenAPI sind nicht der Kernpunkt. Wichtiger ist eine klare Dokumentation
Noch keine Kommentare.