Bessere APIs gestalten
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/healthhttps://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:
200für allgemeinen Erfolg201für erfolgreiche Erstellung400für fehlerhafte Requests des Clients401für nicht autorisierte Requests403für fehlende Berechtigungen404für nicht gefundene Ressourcen429für zu viele Requests5xxfür interne Fehler (sollten vermieden werden)
№ 08 Sinnvolle HTTP-Methoden
POSTzum Erstellen von Ressourcen,POST /usersGETzum Lesen von Ressourcen,GET /users/{id}PATCHfür partielle Aktualisierungen,PATCH /users/{id}PUTfür vollständige Aktualisierungen,PUT /users/{id}DELETEzum 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.