Software Engineering22. Juli 20268 min read

APIs entwerfen, die Entwickler wirklich gern verwenden

Die besten APIs wirken selbstverständlich. Dieser Leitfaden führt durch die Designentscheidungen, die aus einer technischen Schnittstelle etwas machen, zu dem Entwickler immer wieder greifen.

Von Innovation T Team


Die beste API, die Sie je verwendet haben, fühlte sich wahrscheinlich an, als würde sie Ihre Gedanken lesen. Sie rieten den Endpunkt, und er existierte. Sie rieten den Feldnamen, und er war richtig. Fehler sagten Ihnen genau, was schiefgelaufen war. Dieses Gefühl ist kein Glück. Es ist das Ergebnis bewusster Designentscheidungen, getroffen von Menschen, denen die Person auf der anderen Seite der Anfrage am Herzen liegt.

Bei Innovation T entwickeln und integrieren wir APIs über Web-, Mobil- und Cloud-Projekte hinweg, und dieselbe Lektion taucht immer wieder auf: Eine API ist ein Produkt, und ihre Nutzer sind Entwickler. Nehmen Sie deren Zeit und Aufmerksamkeit genauso ernst wie die eines Endnutzers, dann folgt die Akzeptanz. So entwerfen Sie eine Schnittstelle, die Menschen tatsächlich gern verwenden.

Einheitliche Benennung von Ressourcen

Eine API ist ein Vokabular. Ist dieses Vokabular uneinheitlich, wird jeder Endpunkt zu einem kleinen Gedächtnistest. Wählen Sie klare Konventionen und brechen Sie sie niemals.

Verwenden Sie Substantive für Ressourcen, keine Verben. Die HTTP-Methode trägt das Verb bereits. Nutzen Sie Ressourcennamen im Plural, in Kleinbuchstaben, mit Bindestrichen, und verschachteln Sie Beziehungen auf vorhersehbare Weise:

GET    /v1/customers
GET    /v1/customers/42
GET    /v1/customers/42/invoices
POST   /v1/customers/42/invoices
DELETE /v1/invoices/900

Vermeiden Sie es, userId, user_id und UserID über die Nutzdaten hinweg zu vermischen. Wählen Sie eine einzige Schreibweise (camelCase oder snake_case) und wenden Sie sie auf jedes Feld in jeder Antwort an. Einheitlichkeit ist mehr wert als jede einzelne, angeblich "bessere" Wahl, denn sie erlaubt Entwicklern vorherzusagen, was sie noch nicht gelesen haben.

Sinnvolle Statuscodes

Statuscodes sind das erste Signal, das ein Client liest, oft noch bevor er einen Rumpf auswertet. Verwenden Sie sie ehrlich.

  • 200 für ein erfolgreiches Lesen oder Aktualisieren.
  • 201 für eine soeben erstellte Ressource, mit einem Location-Header.
  • 202, wenn Sie eine Aufgabe angenommen haben, die asynchron abgeschlossen wird.
  • 204 für ein erfolgreiches Löschen ohne Rumpf.
  • 400 für fehlerhafte Eingaben, 401 für fehlende oder falsche Anmeldedaten, 403 für authentifiziert, aber nicht berechtigt.
  • 404 für eine Ressource, die nicht existiert, 409 für einen Konflikt wie ein Duplikat.
  • 422 für wohlgeformte Anfragen, die an Validierungsregeln scheitern.
  • 429, wenn der Client die Ratengrenze überschreitet.
  • 500 für Ihre Fehler, niemals für die Fehler des Clients.

Die Todsünde ist, ein 200 OK mit einem im Rumpf versteckten Fehler zurückzugeben. Das zwingt jeden Client, Erfolgsantworten defensiv auszuwerten, und macht den gesamten Sinn von Statuscodes zunichte.

Hilfreiche Fehlerrümpfe

Ein Statuscode sagt, dass etwas schiefgelaufen ist. Ein guter Fehlerrumpf sagt, was, wo und wie man es behebt. Machen Sie Fehler zugleich maschinen- und menschenlesbar:

{
  "error": {
    "type": "validation_error",
    "message": "The request could not be processed.",
    "fields": [
      { "name": "email", "issue": "must be a valid email address" },
      { "name": "age", "issue": "must be greater than or equal to 18" }
    ],
    "requestId": "req_8fa21c"
  }
}

Der stabile type erlaubt Clients, im Code zu verzweigen. Die message hilft einem Menschen, der die Protokolle liest. Das fields-Array verwandelt eine vage Ablehnung in eine umsetzbare Prüfliste. Die requestId erlaubt einem Entwickler, eine einzige Zeichenkette in ein Support-Ticket einzufügen, damit Sie die genaue Anfrage in Ihren Protokollen finden können. Dieses eine Feld spart auf beiden Seiten Stunden.

Vorhersehbare Paginierung und Filterung

Jede Sammlung, die wachsen kann, muss vom ersten Tag an paginiert werden. Die Paginierung später nachzurüsten, ist eine bahnbrechende Änderung, die alle überrascht.

Cursorbasierte Paginierung ist die robusteste Wahl für große oder sich häufig ändernde Datensätze, weil sie keine Zeilen überspringt oder dupliziert, wenn sich die Daten zwischen den Anfragen verschieben:

{
  "data": [
    { "id": "inv_1", "amount": 1200 },
    { "id": "inv_2", "amount": 850 }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6Imludl8yIn0",
    "hasMore": true
  }
}

Der Client übergibt weiterhin ?cursor=..., bis hasMore falsch ist. Offset-Paginierung (?page=3&limit=20) ist einfacher und für kleine, stabile Listen in Ordnung, driftet aber, wenn Zeilen mitten im Scrollen eingefügt oder gelöscht werden.

Die Filterung verdient dieselbe Vorhersehbarkeit. Verwenden Sie Abfrageparameter, die sich wie einfache Sprache lesen, und dokumentieren Sie jeden einzelnen: ?status=paid&created_after=2026-01-01&sort=-amount. Ein vorangestelltes Minus für absteigende Sortierung ist eine kleine Konvention, aber sobald ein Entwickler sie einmal gelernt hat, funktioniert sie überall in Ihrer API.

Idempotenz

Netzwerke fallen auf halber Strecke aus. Ein Client sendet eine Zahlungsanfrage, die Verbindung bricht ab, bevor die Antwort eintrifft, und der Client weiß nicht, ob die Belastung durchging. Ohne Hilfe erzeugt die sichere Annahme (erneut versuchen) doppelte Belastungen.

Idempotenzschlüssel lösen das. Der Client erzeugt einen eindeutigen Schlüssel und sendet ihn als Header bei jeder Anfrage, die nicht von Natur aus sicher zu wiederholen ist:

POST /v1/charges
Idempotency-Key: 5f2c1a90-payment-42

Ihr Server speichert den Schlüssel zusammen mit dem Ergebnis der ersten Anfrage. Trifft derselbe Schlüssel erneut ein, geben Sie die ursprüngliche Antwort zurück, statt die Aktion ein zweites Mal auszuführen. GET, PUT und DELETE sind per Definition idempotent. Es ist POST, das diesen Schutz benötigt, und ihn anzubieten signalisiert, dass Sie ernsthaft über Zuverlässigkeit in der Praxis nachgedacht haben. Das zählt umso mehr für Clients, die als offline-first Mobil-Apps gebaut sind (siehe /blog/offline-first-mobile-apps), bei denen Anfragen in eine Warteschlange gestellt und erneut abgespielt werden, sobald die Verbindung zurückkehrt.

Ratenbegrenzung, die kommuniziert

Ratengrenzen schützen Ihre Infrastruktur, aber ein stummes 429 lehrt Entwickler nichts. Sagen Sie ihnen bei jeder Antwort, wo sie stehen:

RateLimit-Limit: 1000
RateLimit-Remaining: 12
RateLimit-Reset: 1753142400

Wenn Sie eine Anfrage tatsächlich ablehnen, fügen Sie einen Retry-After-Header hinzu, damit Clients sich anmutig zurückziehen können, statt Sie zu bombardieren. Ein wohlerzogener Client ist eine Partnerschaft, und Sie bauen sie auf, indem Sie dem Client die Informationen geben, die er braucht, um sich gut zu verhalten.

Authentifizierung, die zum Anwendungsfall passt

Passen Sie den Mechanismus an den Aufrufer an. Kurzlebige Bearer-Token (OAuth-2.0-Zugriffstoken oder JWTs) eignen sich für nutzerorientierte Apps, in denen Sitzungen ablaufen und erneuert werden. API-Schlüssel eignen sich für Server-zu-Server-Integrationen, in denen ein langlebiges Geheimnis akzeptabel ist. Was auch immer Sie wählen, halten Sie drei Regeln ein: Verlangen Sie überall HTTPS, akzeptieren Sie Anmeldedaten niemals in der Abfragezeichenkette, wo sie in Protokolle gelangen, und geben Sie bei fehlgeschlagener Authentifizierung ein 401 mit einem klaren Grund zurück. Bei der Authentifizierung wird Vertrauen gewonnen oder verloren, machen Sie sie also langweilig und vorhersehbar.

Versionierungsstrategie

Veränderung ist unvermeidlich. Eine Versionierungsstrategie ist Ihr Versprechen, dass Veränderung bestehende Integrationen nicht ohne Vorwarnung bricht.

URL-Versionierung (/v1/, /v2/) ist am sichtbarsten und am leichtesten nachzuvollziehen, weshalb sie die verbreitete Standardwahl bleibt. Header-basierte Versionierung hält URLs sauber, verbirgt aber die Version, sodass sie leichter vergessen wird. Was auch immer Sie wählen, die Disziplin zählt mehr als der Mechanismus: Additive Änderungen (neue optionale Felder, neue Endpunkte) sind sicher und brauchen keine neue Version. Ein Feld zu entfernen, umzubenennen oder einen Typ zu ändern, ist eine bahnbrechende Änderung und erfordert eine neue Version samt einem Auslaufzeitraum. Zweckentfremden Sie ein bestehendes Feld niemals klammheimlich.

Stabilitätsgarantien

Sagen Sie Entwicklern, worauf sie sich verlassen können. Veröffentlichen Sie, welche Teile Ihrer API stabil sind, welche sich in der Beta befinden und wie lange eine veraltete Version noch funktioniert, bevor sie entfernt wird. Eine klare Auslaufrichtlinie, zum Beispiel sechs Monate Vorlaufzeit mit datierten Warnungen in den Antwort-Headern, verwandelt eine beängstigende Migration in eine geplante Aufgabe. Entwickler bauen weitaus bereitwilliger auf einer API auf, der sie vertrauen, dass sie stabil bleibt, als auf einer, die sich ohne Vorwarnung unter ihren Füßen verschieben könnte.

Hervorragende Dokumentation und Beispiele

Die Dokumentation ist der Ort, an dem Entwickler die meiste Zeit mit Ihrer API verbringen, also ist sie der Ort, an dem sich das Design auszahlt oder auseinanderfällt. Die besten Dokumentationen teilen einige Merkmale: eine kopierfertige Anfrage für jeden Endpunkt, ein echtes Antwortbeispiel daneben und klar gekennzeichnete Pflicht- gegenüber optionalen Feldern. Zeigen Sie die Authentifizierung einmal, gleich zu Beginn, in einem ausführbaren Ausschnitt. Bieten Sie einen Schnellstart, der einen Entwickler in unter fünf Minuten zu seinem ersten erfolgreichen Aufruf bringt, denn dieser erste Erfolg verwandelt einen neugierigen Leser in einen überzeugten Nutzer. Interaktive Dokumentation, die jemandem erlaubt, eine echte Anfrage aus dem Browser abzusenden, verwandelt Lesen in Lernen.

REST und die Alternativen

REST ist aus gutem Grund die Standardwahl: Es bildet sich sauber auf HTTP ab, ist zwischenspeicherbar und wird universell verstanden. Der Großteil dieses Artikels geht von REST aus, weil die meisten APIs REST sind.

Es ist nicht die einzige Option. Mit GraphQL können Clients in einem einzigen Hin und Zurück genau die Felder anfordern, die sie benötigen, was bei reichhaltigen, verschachtelten Daten und App-Bildschirmen glänzt, die sich sonst in viele REST-Aufrufe auffächern würden, auf Kosten von Caching-Komplexität und schwererer Abfrageplanung serverseitig. gRPC nutzt binäre Protocol Buffers über HTTP/2 und ist hervorragend für internen Service-zu-Service-Verkehr mit hohem Durchsatz, ist aber für Browser und beiläufiges Erkunden weniger freundlich. Die richtige Wahl hängt von Ihren Konsumenten ab. Eine öffentliche API für ein breites Publikum tendiert zu REST; eine Mobil-App mit komplexen Datenbedürfnissen bevorzugt vielleicht GraphQL; eine Flotte interner Microservices könnte sich auf gRPC vereinheitlichen. Wenn Sie Servicegrenzen und Kommunikationsstile abwägen, geht unser Leitfaden zum Umstieg von /blog/monolith-to-microservices tiefer auf diese Abwägungen ein.

Die Checkliste für API-Design

Führen Sie jede neue API durch diese Liste, bevor Sie sie ausliefern:

  1. Sind Ressourcen mit einheitlichen Substantiven im Plural und in Kleinbuchstaben benannt?
  2. Ist die Feldschreibweise über jeden Endpunkt hinweg identisch?
  3. Bedeutet jeder Statuscode das, was er sollte, ohne Fehler versteckt in einem 200?
  4. Enthalten Fehlerrümpfe einen stabilen Typ, eine menschliche Nachricht, die beanstandeten Felder und eine Anfrage-ID?
  5. Ist jede wachsbare Sammlung paginiert, mit dokumentierter Filterung und Sortierung?
  6. Sind unsichere Operationen durch Idempotenzschlüssel geschützt?
  7. Legen Antworten Ratengrenzen-Header und bei Ablehnung ein Retry-After offen?
  8. Wird die Authentifizierung über HTTPS erzwungen, mit Anmeldedaten außerhalb der URLs?
  9. Gibt es eine klare Versionierungsstrategie und eine veröffentlichte Auslaufrichtlinie?
  10. Kann ein neuer Entwickler in unter fünf Minuten einen erfolgreichen Aufruf aus der Dokumentation heraus tätigen?

Alles zusammengeführt

Jeder Punkt oben läuft auf eine Idee hinaus: Respektieren Sie die Zeit des Entwicklers. Einheitliche Benennung erspart ihm Gedächtnisarbeit, ehrliche Statuscodes ersparen ihm Rätselraten, hilfreiche Fehler ersparen ihm Fehlersuche, Idempotenz erspart ihm Duplikat-Katastrophen, und gute Dokumentation erspart ihm Frust. Tun Sie das konsequent, und Ihre API hört auf, ein technisches Detail zu sein, und wird zu einem Grund, warum Menschen sich für Sie entscheiden.

Wenn Ihr Team eine neue API entwirft, eine veraltete entwirrt oder zwischen REST, GraphQL und gRPC entscheidet, kann Innovation T Ihnen helfen, die Grundlagen richtig zu legen. Entdecken Sie unsere Arbeitsweise auf unserer Leistungen-Seite, oder kontaktieren Sie uns, um über Ihr Projekt zu sprechen.

#API-Design#REST#Entwicklererfahrung#Softwareentwicklung

Bereit, mit Innovation T zu bauen?

Ob Sicherheit, Wachstum oder Engineering, unser Team hilft Ihnen, es gut umzusetzen.