Zum Inhalt springen
Blog

Bessere APIs gestalten

25. August 2023 · 10 Min. Lesezeit · Ronald Blüthl

APIs sind großartig, aber auch extrem schwierig zu entwerfen. Wenn Sie eine API von Grund auf neu erstellen, müssen Sie viele Details richtig umsetzen. Von grundlegenden Sicherheitsaspekten über die Wahl der richtigen HTTP-Methoden, die Implementierung von Authentifizierung bis hin zur Entscheidung, welche Requests und Responses Sie akzeptieren und zurückgeben, die Liste ist lang.

In diesem Beitrag versuche ich, alles zusammenzufassen, was eine gute API ausmacht. Eine API, die Ihre Nutzer gerne verwenden. Alle Tipps sind sprachunabhängig und gelten für jedes Framework und jede Technologie.

№ 01 Seien Sie konsistent

Klingt logisch, ist aber schwer umzusetzen. Die besten APIs sind vorhersehbar. Wenn ein Nutzer einen Endpoint verstanden hat, kann er erwarten, dass ein anderer Endpoint genauso funktioniert.

  • Verwenden Sie einheitliche Schreibweisen für Felder, Ressourcen und Parameter (ich bevorzuge snake_case)
  • Verwenden Sie entweder Plural oder Singular für Ressourcennamen (ich bevorzuge Plural): /users/{id}, /orders/{id}
  • Verwenden Sie dieselben Authentifizierungsmethoden für alle Endpoints
  • Verwenden Sie dieselben HTTP-Header in der gesamten API
  • Verwenden Sie dieselben HTTP-Statuscodes basierend auf der Art der Antwort
  • Verwenden Sie dieselben HTTP-Methoden für gleichartige Aktionen

№ 02 ISO 8601 UTC-Datumsformate

Beim Umgang mit Datum und Uhrzeit sollten APIs immer ISO 8601-formatierte Zeichenketten zurückgeben. Die Darstellung in einer bestimmten Zeitzone ist Aufgabe des Clients.

{
  "published_at": "2022-03-03T21:59:08Z"
}

№ 03 Standardmäßig autorisieren

Jeder Endpoint sollte standardmäßig eine Autorisierung erfordern. Die meisten Endpoints setzen einen authentifizierten Nutzer voraus, daher ist diese Voreinstellung sinnvoll. Wenn ein Endpoint öffentlich erreichbar sein muss, setzen Sie diesen Endpoint explizit auf „nicht autorisiert erforderlich".

№ 04 Health-Check-Endpoint

Stellen Sie einen Endpoint bereit (zum Beispiel GET /health), der feststellt, ob ein Service funktionsfähig ist. Dieser Endpoint kann von Load Balancern aufgerufen werden, um bei einem Ausfall reagieren zu können.

№ 05 Versionieren Sie die API

Stellen Sie sicher, dass Sie Ihre API versionieren und die Version bei jedem Request mitgeben, damit Nutzer von Änderungen an einer anderen Version nicht betroffen sind. API-Versionen können über HTTP-Header oder Query-/Pfadparameter übergeben werden. Auch die erste Version (1.0) sollte explizit versioniert werden.

  • https://api.averagecompany.com/v1/health
  • https://api.averagecompany.com/health?api_version=1.0

№ 06 API-Key-Authentifizierung

Wenn eine API von Dritten aufgerufen werden soll, ist es sinnvoll, die Authentifizierung über API-Keys zu ermöglichen. API-Keys sollten über einen benutzerdefinierten HTTP-Header (wie Api-Key) übergeben werden. Sie sollten ein Ablaufdatum haben, und es muss möglich sein, aktive Schlüssel zu widerrufen.

№ 07 Sinnvolle HTTP-Statuscodes

Verwenden Sie gängige HTTP-Statuscodes, um den Erfolg oder Misserfolg eines Requests anzuzeigen. Einige Beispiele:

  • 200 für allgemeinen Erfolg
  • 201 für erfolgreiche Erstellung
  • 400 für fehlerhafte Requests des Clients
  • 401 für nicht autorisierte Requests
  • 403 für fehlende Berechtigungen
  • 404 für nicht gefundene Ressourcen
  • 429 für zu viele Requests
  • 5xx für interne Fehler (sollten vermieden werden)

№ 08 Sinnvolle HTTP-Methoden

  • POST zum Erstellen von Ressourcen, POST /users
  • GET zum Lesen von Ressourcen, GET /users/{id}
  • PATCH für partielle Aktualisierungen, PATCH /users/{id}
  • PUT für vollständige Aktualisierungen, PUT /users/{id}
  • DELETE zum Löschen, DELETE /users/{id}

№ 09 Selbsterklärende, einfache Namen

Die meisten Endpoints sind ressourcenorientiert und sollten entsprechend benannt werden.

Gut: GET /users, DELETE /users/{id}, user.first_name

Schlecht: GET /getUser, POST /updateUser, user.firstName

№ 10 Standardisierte Fehlerantworten

Bei Fehlern immer eine standardisierte Fehlerantwort zurückgeben, die detailliertere Informationen darüber enthält, was schiefgelaufen ist. So können Nutzer immer dieselbe Struktur erwarten und entsprechend reagieren.

// Response <= 404 Not Found
{
  "code": "user/not_found",
  "message": "A user with the ID 4TL011ax could not be found."
}

№ 11 Erstellte Ressourcen bei POST zurückgeben

Es ist empfehlenswert, die erstellte Ressource nach einem POST-Request zurückzugeben. Die zurückgegebene Ressource spiegelt den aktuellen Zustand der zugrundeliegenden Datenquelle wider und enthält aktuellere Informationen (wie etwa eine generierte ID).

№ 12 PATCH bevorzugen

PATCH-Requests nehmen partielle Aktualisierungen vor, während PUT eine bestehende Ressource vollständig ersetzt. PATCH ist in der Regel sinnvoller, bei PUT muss die gesamte Ressource mitgesendet werden, was netzwerkintensiver und fehleranfälliger ist.

№ 13 So spezifisch wie möglich

Beim Entwerfen von Endpoints, bei der Benennung von Feldern und bei der Entscheidung, welche Requests und Responses akzeptiert werden, so spezifisch wie möglich sein. Wenn ein PATCH-Request nur zwei Felder akzeptiert (name und description), besteht keine Gefahr, ihn falsch zu verwenden und Daten zu korrumpieren.

№ 14 Paginierung

Paginieren Sie alle Requests, die eine Sammlung von Ressourcen zurückgeben, und verwenden Sie dieselbe Antwortstruktur:

// Request => GET /users?page_number=1&page_size=15

// Response <= 200 OK
{
  "page_number": 1,
  "page_size": 15,
  "count": 378,
  "data": [],
  "total_pages": 26,
  "has_previous_page": true,
  "has_next_page": true
}

№ 15 Erweitern von Ressourcen ermöglichen

Ermöglichen Sie Nutzern, zugehörige Daten über einen Query-Parameter namens expand zu laden. Das ist besonders nützlich, um Roundtrips zu vermeiden und alle für eine bestimmte Aktion benötigten Daten in einem einzigen Aufruf zu laden.

Klingt nach Ihrem Vorhaben? Prototyp um 2.900 €. Erstgespräch buchen