API Design Best Practices
API Design: Best Practices für saubere REST APIs
Eine gut designte API ist intuitiv und konsistent. Dieser Guide zeigt bewährte Patterns für REST API Design.
Resourcen-Naming
Substantive, keine Verben
❌ /getUsers ❌ /createUser ❌ /deleteUser/123 ✅ GET /users (alle User) ✅ POST /users (User erstellen) ✅ GET /users/123 (einzelner User) ✅ PUT /users/123 (User aktualisieren) ✅ DELETE /users/123 (User löschen)
Plural für Collections
❌ /user ❌ /user/123 ✅ /users ✅ /users/123
Verschachtelung für Beziehungen
GET /users/123/orders (Bestellungen eines Users) GET /orders/456/items (Items einer Bestellung) POST /users/123/orders (Neue Bestellung für User)
HTTP-Methoden richtig nutzen
| Methode | Aktion | Idempotent? |
|---|---|---|
GET |
Lesen | Ja |
POST |
Erstellen | Nein |
PUT |
Vollständig ersetzen | Ja |
PATCH |
Teilweise aktualisieren | Ja |
DELETE |
Löschen | Ja |
API Versionierung
# In URL (empfohlen, am klarsten) /api/v1/users /api/v2/users # In Header Accept: application/vnd.myapi.v1+json # In Query Parameter /api/users?version=1
Pagination
GET /api/v1/users?page=2&per_page=20
{
"data": [...],
"pagination": {
"page": 2,
"per_page": 20,
"total": 150,
"total_pages": 8
},
"links": {
"first": "/api/v1/users?page=1",
"prev": "/api/v1/users?page=1",
"next": "/api/v1/users?page=3",
"last": "/api/v1/users?page=8"
}
}
Cursor-basierte Pagination (für große Datenmengen)
GET /api/v1/users?cursor=abc123&limit=20
{
"data": [...],
"next_cursor": "def456",
"has_more": true
}
Filtering & Sorting
# Filtering GET /api/v1/users?status=active&role=admin GET /api/v1/products?price_min=10&price_max=100 GET /api/v1/orders?created_after=2024-01-01 # Sorting GET /api/v1/users?sort=created_at GET /api/v1/users?sort=-created_at (absteigend) GET /api/v1/users?sort=name,-created_at # Field Selection (Sparse Fieldsets) GET /api/v1/users?fields=id,name,email
Response-Format
Erfolgreiche Responses
// Einzelne Resource (GET /users/123)
{
"data": {
"id": 123,
"name": "Max Mustermann",
"email": "max@example.com",
"created_at": "2024-01-15T10:30:00Z"
}
}
// Collection (GET /users)
{
"data": [
{ "id": 123, "name": "Max" },
{ "id": 124, "name": "Anna" }
],
"pagination": { ... }
}
// Erstellt (POST /users)
// HTTP 201 Created
{
"data": { "id": 125, "name": "Tom" }
}
Fehler-Responses
// HTTP 400 Bad Request
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validierung fehlgeschlagen",
"details": [
{ "field": "email", "message": "Ungültiges E-Mail-Format" },
{ "field": "password", "message": "Mindestens 8 Zeichen" }
]
}
}
// HTTP 404 Not Found
{
"error": {
"code": "NOT_FOUND",
"message": "User mit ID 999 nicht gefunden"
}
}
// HTTP 401 Unauthorized
{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentifizierung erforderlich"
}
}
HTTP Status Codes
| Code | Verwendung |
|---|---|
| 200 | Erfolg (GET, PUT, PATCH) |
| 201 | Erstellt (POST) |
| 204 | Erfolg ohne Body (DELETE) |
| 400 | Bad Request (Validierung) |
| 401 | Nicht authentifiziert |
| 403 | Verboten (keine Berechtigung) |
| 404 | Nicht gefunden |
| 422 | Unprocessable Entity |
| 429 | Too Many Requests |
| 500 | Server Error |
Authentifizierung
# Bearer Token (empfohlen) Authorization: Bearer eyJhbGciOiJIUzI1NiIs... # API Key (für Server-zu-Server) X-API-Key: sk_live_abc123 # Nie im Query Parameter! ❌ /api/users?api_key=secret
Rate Limiting Headers
HTTP/1.1 200 OK X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1699999999
API Dokumentation
# OpenAPI/Swagger empfohlen
openapi: 3.0.0
info:
title: My API
version: 1.0.0
paths:
/users:
get:
summary: Liste aller User
parameters:
- name: page
in: query
schema:
type: integer
responses:
200:
description: Erfolg
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
Checkliste
✅ API Design Checkliste:
- Konsistentes Naming (plural, kebab-case)
- HTTP-Methoden korrekt verwendet
- Versionierung implementiert
- Einheitliches Response-Format
- Aussagekräftige Fehlermeldungen
- Pagination für Listen
- Rate Limiting vorhanden
- Dokumentation aktuell