API-Design
Den richtigen API-Typ wählen
| Typ | Am besten geeignet für | Vermeiden bei |
|---|
| REST | Öffentliche APIs, CRUD, einfache Clients, IoT | Komplexe verschachtelte Daten, schnelle Schema-Änderungen |
| GraphQL | Mobile Apps, komplexe verschachtelte Daten, mehrere Clients | Einfaches CRUD, kleine Teams, die neu darin sind |
| tRPC | TypeScript-Monorepos, interne Full-Stack-TS-APIs | Nicht-TypeScript-Clients, öffentliche APIs |
| gRPC | Hochleistungs-Mikroservice-Kommunikation, Streaming | Browser-Clients, einfache Anwendungsfälle |
REST-API-Design
URL-Konventionen
GET /users ← Liste
GET /users/{id} ← Einzelnes
POST /users ← Erstellen
PUT /users/{id} ← Ersetzen
PATCH /users/{id} ← Teilweises Aktualisieren
DELETE /users/{id} ← Löschen
# Verschachtelte Ressourcen
GET /users/{id}/orders
POST /users/{id}/orders
# Aktionen (wenn REST-Verben nicht ausreichen)
POST /orders/{id}/cancel
POST /users/{id}/activate
HTTP-Statuscodes
| Code | Verwenden, wenn |
|---|
| 200 | Erfolgreiches GET, PUT, PATCH |
| 201 | Erfolgreiches POST, das erstellt |
| 204 | Erfolgreiches DELETE (kein Body) |
| 400 | Validierungsfehler, fehlerhafte Anfrage |
| 401 | Fehlende/ungültige Authentifizierung |
| 403 | Authentifiziert, aber nicht autorisiert |
| 404 | Ressource nicht gefunden |
| 409 | Konflikt (Duplikat, Versionskonflikt) |
| 422 | Nicht verarbeitbare Entität (semantische Fehler) |
| 429 | Ratenlimit überschritten |
| 500 | Unerwarteter Serverfehler |
Antwort-Hülle
{
"data": [...],
"meta": { "total": 100, "page": 1, "perPage": 20 }
}
{ "data": { "id": "1", "name": "James" } }
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validierung fehlgeschlagen",
"details": [{ "field": "email", "issue": "Ungültiges Format" }]
}
}
API-Design-Prinzipien
Versionierungsstrategie
# URL-Versionierung (am sichtbarsten, am einfachsten zu routen)
/v1/users
/v2/users
# Header-Versionierung (sauberere URLs)
Accept: application/vnd.api+json;version=2
Brechen Sie niemals bestehende Clients. Kündigen Sie die Abschaffung an, dann entfernen Sie.
Paginierung
# Offset (einfach, gut für kleine Datensätze)
GET /posts?page=2&perPage=20
# Cursor (schnell für große Datensätze, für unendliches Scrollen verwenden)
GET /posts?cursor=eyJpZCI6MTAwfQ&limit=20
Filtern & Sortieren
GET /orders?status=pending&userId=123
GET /products?sort=-price,name # - Präfix = absteigend
GET /products?fields=id,name,price # Sparse Fieldsets
Idempotenz
# Idempotenzschlüssel für nicht-idempotente Operationen einfügen
POST /payments
Idempotency-Key: unique-client-generated-uuid
GraphQL-Design
Schema-Design-Regeln
- Beschreiben Sie die Geschäftsdomäne, nicht die DB-Struktur
- Verwenden Sie das Verbindungsmuster für Listen (paginierungsbereit)
- Mutationen geben das geänderte Objekt zurück
- Verwenden Sie Enums für endliche Wertemengen
- Fügen Sie Beschreibungen zu allen Typen und Feldern hinzu
type Query {
user(id: ID!): User
users(filter: UserFilter, pagination: PaginationInput): UserConnection!
}
type Mutation {
createUser(input: CreateUserInput!): CreateUserPayload!
updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
API-Sicherheitscheckliste