REST-API-Design mit Claude Code: Endpunkte, Fehler, Pagination, Idempotenz
REST-APIs mit Claude Code vor der Implementierung entwerfen: OpenAPI, Fehlerformat, Pagination und Idempotenz.
Eine REST-API ist nicht fertig, nur weil ein paar Routen existieren. Vor der Implementierung muss klar sein, was als Ressource gilt, welche HTTP-Methode jede Aktion nutzt, welche Antwort bei Fehlern zurückkommt, wie Listen paginiert werden und wie wiederholte Anfragen behandelt werden. Wenn diese Entscheidungen offen bleiben, schreibt Claude Code zwar schnell Code, aber Frontend, Mobile-App und Partnerintegration lesen jeweils einen anderen Vertrag heraus.
Dieser Artikel zeigt, wie du mit Claude Code das REST-API-Design vor dem Coding festziehst. REST steht für Representational State Transfer. Praktisch bedeutet das hier: Ressourcen wie Bestellungen, Benutzer oder Rechnungen werden nach festen HTTP-Regeln bedient. Die Ressource ist das Objekt, die Methode ist die Aktion, der Statuscode ist das Ergebniszeichen.
Als offizielle Referenzen eignen sich MDNs HTTP request methods, MDNs HTTP response status codes und die OpenAPI Specification. Am 3. Juni 2026 verweist die OpenAPI-latest-Seite auf 3.2.0; das Beispiel nutzt bewusst openapi: 3.1.0, weil viele Linter und Generatoren damit noch verlässlicher arbeiten.
Für die Implementierung passen API-Entwicklung mit Claude Code, Claude Code API-Tests und Claude Code Code Review dazu. Wiederverwendbare Vorlagen und Checklisten findest du unter /products/, Team-Training für API-Design-Reviews unter /training/.
Erst Die Begriffe Klären
Einsteiger stolpern oft, weil REST-Begriffe ähnlich klingen. Bevor Claude Code implementiert, sollte das Team diese Wörter gleich verwenden.
| Begriff | Einfache Erklärung | Beispiel |
|---|---|---|
| Ressource | Das Substantiv, mit dem die API arbeitet | orders, customers |
| Endpunkt | URL plus HTTP-Methode | GET /v1/orders |
| Methode | Das HTTP-Verb für die gewünschte Aktion | GET, POST, PATCH |
| Statuscode | Zahl für Erfolg, Eingabefehler, fehlende Anmeldung und mehr | 200, 201, 400, 404 |
| Validierung | Prüfung, ob die Anfrage die richtige Form hat | E-Mail-Format, Mindestmenge |
| Idempotenz | Gleiche Anfrage mehrfach senden, ohne den Endzustand zu verändern | Eine Bestellung pro Schlüssel |
Claude Code kann Kontext gut lesen, garantiert aber nicht, dass es deine Designabsicht trifft. “Baue die Order-Create-API” kann zu /createOrder, /orders/create oder POST /orders führen. Begriffe und Regeln vorab zu liefern, verbessert die spätere Implementierung deutlich.
Drei Use Cases Entscheiden Das Design
Die gleiche Bestell-API braucht je nach Nutzung andere Prioritäten.
Der erste Use Case ist eine B2B-SaaS-Integration. Wenn ein Partner denselben nächtlichen CSV-Job erneut sendet, braucht POST /v1/orders einen Idempotency-Key, damit keine doppelten Bestellungen entstehen. Solche Wiederholungen passieren besonders bei Störungen; Idempotenz lässt sich später nur schwer sauber ergänzen.
Der zweite Use Case ist eine Admin-Liste. Eine Mitarbeiterin filtert nach status=paid, geht auf die nächste Seite, während jemand anderes eine Bestellung anlegt. page=2 kann dann verrutschen. Besser ist Cursor-Pagination mit limit und after, kombiniert mit einer stabilen Sortierung wie createdAt desc, id desc.
Der dritte Use Case ist eine mobile App. Alte App-Versionen bleiben oft monatelang installiert, daher dürfen Feldnamen in Antworten nicht abrupt wechseln. Neue Pflichtfelder oder ein neues Fehlerformat gehören in /v2, während der /v1-Vertrag in OpenAPI erhalten bleibt. Kleine optionale Felder benötigen normalerweise keine neue Version.
Ein vierter Fall sind interne Service-APIs. Consumer lassen sich dort leichter gemeinsam aktualisieren, aber Monitoring und Alarme sind oft schwächer. Auch intern führen uneinheitliche Statuscodes und Fehlerformate dazu, dass jeder Aufrufer Sonderlogik schreibt.
Den Designfluss Sichtbar Machen
Fixiere das Design in dieser Reihenfolge, bevor Claude Code die Aufgabe bekommt. So driftet die Implementierung beim Bearbeiten der Dateien weniger leicht vom Vertrag weg.
flowchart TD
A["Use cases"] --> B["Resources and endpoints"]
B --> C["OpenAPI contract"]
C --> D["Errors, pagination, idempotency"]
D --> E["Claude Code implementation"]
E --> F["Tests and review"]
Endpunkttabelle Vor Dem Coding Fixieren
Das erste Ergebnis ist keine Implementierung, sondern eine Endpunkttabelle. Übergib sie an Claude Code, damit Routing, OpenAPI, Tests und Dokumentation aus demselben Vertrag entstehen.
| Zweck | Methode und Pfad | Erfolg | Wichtige Regel |
|---|---|---|---|
| Bestellungen listen | GET /v1/orders?status=paid&limit=20&after=ord_123 | 200 OK | Cursor-Pagination mit stabiler Sortierung |
| Bestellung erstellen | POST /v1/orders | 201 Created | Idempotency-Key akzeptieren und Location zurückgeben |
| Bestellung lesen | GET /v1/orders/{orderId} | 200 OK | Fehlende Ressource wird 404 |
| Bestellung aktualisieren | PATCH /v1/orders/{orderId} | 200 OK | Teilupdate; leeres Patch ist 400 |
| Bestellung stornieren | POST /v1/orders/{orderId}/cancel | 200 OK | Zustandswechsel konsistent behandeln |
Die Grundregel lautet: Substantive in die URL, Verben in die Methode. Manche fachlichen Aktionen, etwa eine Stornierung, sind als klarer Unterbefehl verständlicher als ein erzwungenes DELETE. Entscheidend ist, die Ausnahme aufzuschreiben und ähnliche Aktionen gleich zu benennen.
OpenAPI Als Designquelle Nutzen
OpenAPI beschreibt Pfade, Parameter, Requests und Responses maschinenlesbar. Wenn du Claude Code sagst, dass dieser OpenAPI-Vertrag die Quelle der Wahrheit ist, begrenzt du den Implementierungsspielraum auf das Nötige.
openapi: 3.1.0
info:
title: Acme Orders API
version: 1.0.0
servers:
- url: https://api.example.com
paths:
/v1/orders:
get:
operationId: listOrders
summary: List orders
parameters:
- $ref: "#/components/parameters/StatusParam"
- $ref: "#/components/parameters/LimitParam"
- $ref: "#/components/parameters/AfterParam"
responses:
"200":
description: Orders are returned in a stable cursor order.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderListResponse"
"400":
$ref: "#/components/responses/BadRequest"
post:
operationId: createOrder
summary: Create an order
parameters:
- $ref: "#/components/parameters/IdempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateOrderRequest"
responses:
"201":
description: Order created.
headers:
Location:
schema:
type: string
description: URL of the created order.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"400":
$ref: "#/components/responses/BadRequest"
"409":
$ref: "#/components/responses/Conflict"
/v1/orders/{orderId}:
get:
operationId: getOrder
summary: Get one order
parameters:
- $ref: "#/components/parameters/OrderId"
responses:
"200":
description: Order found.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"404":
$ref: "#/components/responses/NotFound"
patch:
operationId: updateOrder
summary: Update mutable order fields
parameters:
- $ref: "#/components/parameters/OrderId"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateOrderRequest"
responses:
"200":
description: Order updated.
content:
application/json:
schema:
$ref: "#/components/schemas/OrderResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
components:
parameters:
OrderId:
name: orderId
in: path
required: true
schema:
type: string
StatusParam:
name: status
in: query
schema:
type: string
enum: [draft, paid, canceled]
LimitParam:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 20
AfterParam:
name: after
in: query
schema:
type: string
description: Cursor returned by the previous response.
IdempotencyKey:
name: Idempotency-Key
in: header
required: false
schema:
type: string
minLength: 16
maxLength: 128
schemas:
CreateOrderRequest:
type: object
required: [customerId, items]
properties:
customerId:
type: string
items:
type: array
minItems: 1
items:
type: object
required: [sku, quantity]
properties:
sku:
type: string
quantity:
type: integer
minimum: 1
UpdateOrderRequest:
type: object
minProperties: 1
properties:
status:
type: string
enum: [draft, paid, canceled]
OrderResponse:
type: object
required: [data]
properties:
data:
$ref: "#/components/schemas/Order"
OrderListResponse:
type: object
required: [data, pageInfo]
properties:
data:
type: array
items:
$ref: "#/components/schemas/Order"
pageInfo:
type: object
required: [nextCursor, hasMore]
properties:
nextCursor:
type: [string, "null"]
hasMore:
type: boolean
Order:
type: object
required: [id, status, totalCents, createdAt]
properties:
id:
type: string
status:
type: string
totalCents:
type: integer
createdAt:
type: string
format: date-time
ErrorResponse:
type: object
required: [error]
properties:
error:
type: object
required: [code, message, requestId]
properties:
code:
type: string
message:
type: string
requestId:
type: string
details:
type: array
items:
type: object
responses:
BadRequest:
description: Request validation failed.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
Conflict:
description: Idempotency key conflicts with a different request.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
NotFound:
description: Resource was not found.
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
Speichere das als openapi.yaml und gib Claude Code mit, keine Implementierung vorzuschlagen, die davon abweicht. Danach kann etwa npx @redocly/cli lint openapi.yaml Syntax und Referenzen prüfen. Wenn TypeScript-Typen oder Clients generiert werden, sollte trotzdem zuerst die Bedeutung der Endpunkttabelle geprüft werden.
Fehler Und Statuscodes Vereinheitlichen
Der Statuscode ist das äußere HTTP-Signal. Der JSON-Body enthält die Details für Menschen und Programme. 200 OK mit { "success": false } lässt Monitoring, SDKs und Retry-Logik einen Fehler als Erfolg behandeln. Lege vorher fest: Eingabefehler sind 400, fehlende Anmeldung 401, fehlende Berechtigung 403, fehlende Ressource 404, Konflikt oder Idempotenzproblem 409.
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Request body has invalid fields.",
"requestId": "req_01J0RESTAPI001",
"details": [
{
"field": "items[0].quantity",
"reason": "must be greater than or equal to 1"
}
]
}
}
{
"error": {
"code": "IDEMPOTENCY_CONFLICT",
"message": "The same Idempotency-Key was used with a different request body.",
"requestId": "req_01J0RESTAPI002"
}
}
{
"error": {
"code": "ORDER_NOT_FOUND",
"message": "Order was not found.",
"requestId": "req_01J0RESTAPI003"
}
}
Für Einsteiger: code ist der kurze Name, auf den Programme verzweigen, message ist die Erklärung für Log oder UI, und requestId hilft dem Support, Serverlogs zu finden. details brauchst du vor allem bei Validierungsfehlern auf Feldebene.
Pagination, Idempotenz Und Versionierung Nicht Offenlassen
Listen-APIs brauchen Pagination von Beginn an. Alle Bestellungen zurückzugeben funktioniert bei kleinen Datenmengen, wird aber später zur Breaking Change. Bei Cursor-Pagination übergibt der Client das nextCursor der letzten Antwort als neues after.
{
"data": [
{
"id": "ord_100",
"status": "paid",
"totalCents": 4800,
"createdAt": "2026-06-03T09:00:00Z"
}
],
"pageInfo": {
"nextCursor": "ord_099",
"hasMore": true
}
}
Idempotenz verhindert doppelte Wirkung durch wiederholte Requests. Gerade POST /orders wird nach Netzwerkfehlern erneut gesendet. Speichere Idempotency-Key und einen Hash des Request-Bodys für begrenzte Zeit. Gleicher Key und gleicher Body liefern das vorige Ergebnis; gleicher Key mit anderem Body liefert 409.
Versionierung gibt Nutzern Migrationszeit. Entfernte Pflichtfelder, geänderte Typen, andere Standardsortierung oder neue Pflichtfelder im Request sind Breaking Changes und gehören nach /v2. Ein zusätzliches optionales Antwortfeld kann meist in /v1 bleiben.
Claude Code Zur Designprüfung Auffordern
Vor der Implementierung hilft ein konkreter Review-Prompt.
Review this OpenAPI design.
Check:
- Resource names are nouns
- HTTP methods and status codes match MDN semantics
- 400/401/403/404/409/500 errors share the same JSON shape
- List pagination is unambiguous
- POST creation endpoints that need idempotency keys are identified
- No response change breaks the v1 contract
- Return a table of issues to fix before TypeScript implementation and tests
So arbeitet Claude Code zuerst als Design-Reviewer, bevor Dateien geändert werden. Erst nach dem Speichern der geprüften OpenAPI sollte die Implementierung folgen.
Häufige Fehler
Fehler 1 sind aktionsartige Endpunkte. Wenn POST /createOrder, POST /updateOrderStatus und GET /deleteOrder nebeneinanderstehen, sind Ressource und Aktion kaum noch lesbar. Nutze lieber POST /v1/orders, PATCH /v1/orders/{orderId} und DELETE /v1/orders/{orderId} und dokumentiere Ausnahmen.
Fehler 2 sind uneinheitliche Statuscodes. Wenn schlechte Eingaben 500, fehlende Ressourcen 200 und erfolgreiche Erstellung mal 200, mal 201 liefern, können Clients nicht sauber verzweigen. Vereinheitliche Erfolgs- und Fehlercodes.
Fehler 3 ist unklare Pagination. Wenn page=2 nicht sagt, ob nach Erstellzeit oder Aktualisierungszeit sortiert wird, führen neue Daten zu Duplikaten oder Lücken. Sortierung, maximales limit und Next-Page-Logik gehören in die Spezifikation.
Fehler 4 ist Validierung nur im Code. Wenn quantity >= 1 nur in der Implementierung steht, können Frontend und generierte SDKs die Regel nicht nutzen. Bedingungen gehören in Spezifikation und Code.
Review-Checkliste
- Ressourcennamen sind konsistente Pluralnomen
- Methoden entsprechen der Bedeutung von
GET,POST,PATCHundDELETE - Erfolgscodes unterscheiden
200,201und204 400,401,403,404,409und500nutzen dieselbe JSON-Form- Listen-APIs enthalten
limit,after,nextCursorundhasMore - Standardwert und Maximum für
limitsind dokumentiert - Create-Endpunkte erzeugen bei Retry keine Duplikate
- Kriterien für Breaking Changes nach
/v2sind festgehalten - Validierungsregeln stehen in OpenAPI
- Endpunkttabelle und OpenAPI stimmen überein, bevor Claude Code startet
REST-API-Design bedeutet nicht, schöne URLs zu malen. Es bedeutet, Versprechen an Nutzer in verständlichen Text und maschinenlesbare Spezifikation zu übersetzen. Claude Code beschleunigt die Umsetzung, aber welche Versprechen das System halten muss, bleibt eine menschliche Designentscheidung.
Beim praktischen Test an Masas Bestell-API reduzierte die Reihenfolge aus OpenAPI, Endpunkttabelle und Fehler-JSON vor der Claude-Code-Implementierung die Review-Schleifen spürbar. Weil Idempotency-Key und Cursor-Pagination schon im Design standen, mussten doppelte Bestellungen und fehlende Listeneinträge später nicht mehr nachträglich repariert werden.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Permission Safety Ladder: Zugriff kontrolliert erweitern
Von read-only zu begrenzten Änderungen, Prüfbefehlen und Deploy-Checks mit klarer Kontrolle.
Claude Code Small PR Proof Pack: kleine Änderungen reviewbar machen
Ein Proof Pack für Claude-Code-PRs: Diff, Checks, öffentliche URL, CTA-Pfad und Rollback.
Claude-Code-Review-Gate vor dem Commit
Vor dem Commit mit Claude Code prüfen: Diff, Build, öffentliche URL, Gumroad-Links, Beratung-CTA, fehlende Tests und fremde Dateien.