API — CRUD-Patterns
Standard-Endpoints pro Resource
GET /api/customers # Liste
GET /api/customers/:id # Detail
POST /api/customers # Anlegen
PATCH /api/customers/:id # Teil-Update
PUT /api/customers/:id # Voll-Replace (selten)
DELETE /api/customers/:id # Soft-Delete
Listen + Pagination
GET /api/customers?page=1&limit=50&sort=createdAt:desc
Response:
{
"data": [...],
"meta": {
"page": 1,
"limit": 50,
"total": 234,
"pages": 5
}
}
Cursor-basiert (für sehr große Listen):
GET /api/customers?cursor=eyJ...&limit=100
Filter
Einfach (Query-Param)
?status=active
?createdAt[gte]=2026-01-01
?name[contains]=Müller
Komplex (POST-Body)
POST /api/customers/search
{
"filter": {
"AND": [
{ "status": "active" },
{ "OR": [
{ "name": { "contains": "Müller" } },
{ "ustId": "DE123" }
]
}
]
},
"sort": [{ "field": "createdAt", "order": "desc" }],
"include": ["locations", "primaryContact"],
"page": 1,
"limit": 50
}
Felder begrenzen (sparse fieldsets)
GET /api/customers?fields=id,name,email
Beziehungen einbinden (include)
GET /api/customers/:id?include=locations,banks,primaryContact
Gibt verschachtelte Objekte zurück.
Anlegen
POST /api/customers
{
"name": "Beispiel GmbH",
"ustId": "DE123456789",
"address": { "street": "...", "city": "Stuttgart", "zip": "70xxx" }
}
Response: 201 + neuer Datensatz.
Teil-Update
PATCH /api/customers/:id
{
"name": "Beispiel AG"
}
Nur die übergebenen Felder werden geändert.
Soft-Delete
DELETE /api/customers/:id
Setzt deletedAt-Flag. Datensatz im Papierkorb. Wiederherstellbar via:
POST /api/customers/:id/restore
Bulk-Operationen
Bulk-Create
POST /api/customers/bulk
[
{ "name": "Kunde 1", ... },
{ "name": "Kunde 2", ... }
]
Response: pro Item Status (success / error).
Bulk-Update
PATCH /api/customers/bulk
{
"filter": { "status": "inactive" },
"update": { "tags": ["archive"] }
}
Bulk-Delete
DELETE /api/customers/bulk
{ "ids": ["uuid1", "uuid2", ...] }
Idempotenz
Für POST/PATCH mit Idempotency-Key:
POST /api/customers
Idempotency-Key: my-unique-key-123
Mehrfache Aufrufe mit gleichem Key → gleiche Response, kein Doppel-Anlegen.
Validation
400-Errors mit Detail:
{
"error": {
"code": "VALIDATION",
"message": "Validation failed",
"details": {
"name": ["Pflichtfeld"],
"ustId": ["Format ungültig"]
}
}
}
Sub-Routen pro Resource
GET /api/customers/:id/locations
GET /api/customers/:id/banks
POST /api/customers/:id/sales-documents
Sub-Routen haben oft eigene CASL-Subjects (z.B. view:CustomerLocation).