Die go~mus API antwortet bei Fehlern mit einem passenden HTTP-Status und einem JSON-Body in einem von zwei Schemata. Diese Seite zeigt, welche Codes in der Praxis auftreten, wie der Body aussieht, und wie du pro Fehlerklasse reagieren sollten.
Status-Codes im Überblick
| Code | Wann | Retry sinnvoll? |
|---|---|---|
200 / 201 | Erfolg | - |
202 Accepted | Asynchroner Prozess läuft (z.B. Dokument-Virenscan), Ergebnis später abholen | Ja, nach kurzem Backoff |
401 Unauthorized | Token fehlt, abgelaufen oder ungültig | Nein, Token tauschen |
403 Forbidden | Token gültig, aber Permission fehlt | Nein, mit anderem User/Permission probieren |
404 Not Found | Resource existiert nicht, oder Route ungültig | Nein, ID prüfen |
410 Gone | Resource war da, ist nicht mehr verfügbar (z.B. abgelaufenes Dokument) | Nein |
422 Unprocessable Entity | Validierungs- oder Business-Logic-Fehler (häufigster Fehlerfall) | Bedingt - nur wenn die Ursache transient ist (siehe unten) |
5xx | Serverseitiger Fehler | Mit exponential Backoff bis 3-5 Versuche |
429 Rate-Limit haben wir derzeit nicht aktiv im Einsatz. Wenn du API-Calls bündeln, planst du trotzdem moderate Concurrency ein.
Body-Format
Zwei Varianten, je nach Endpoint:
Einfacher Fehler
{
"error": "reservation not valid anymore"
}
Das ist die häufigste Form - vor allem bei 422 und 401. Eine kurze, menschenlesbare Botschaft, kein Maschinen-Code, keine Locale-Negotiation. dein solltet die Botschaft loggen, aber für End-User-Anzeige eigene Texte mappen.
Fehler mit Feldliste
{
"error": "customer could not be saved",
"errors": [
"Email can't be blank",
"Phone is too short (minimum is 5 characters)"
]
}
Bei Validierungs-Fehlern auf nested Objekten (Customers, Orders, Requests, Contacts) kommt zusätzlich ein errors-Array mit Feld-Validierungen. Die Strings sind nicht maschinenlesbar - sie sind direkt aus der ActiveRecord-Validierung. Für End-User-Anzeige deine eigenen Texte.
Fehlerklassen mit Beispielen
401 - Token-Probleme
{ "error": "authentication error; no customer or no user present" }
Häufige Ursachen:
- Authorization-Header fehlt komplett
- Bearer-Token tippfehler oder abgelaufen
- Token aus einer anderen Instance benutzt (Tokens sind instance-scoped)
Reaktion: nicht retryen, frisches Token holen. Hilfreich beim Debuggen: die letzten 4 Zeichen des verwendeten Tokens loggen, dann siehst du im Vergleich, welcher Token gerade aktiv war.
422 - Validierung und Business-Logic
{ "error": "reservation is invalid: ticket is required, quantity must be > 0" }
oder
{ "error": "reservation not possible" }
Die typischen Fälle:
- Pflichtfelder fehlen im POST/PUT-Body
- Werte außerhalb des erlaubten Bereichs (Datum in der Vergangenheit, Quantity > Capacity)
- State-Konflikte: Reservation abgelaufen, Slot inzwischen ausgebucht, Order schon finalisiert
- Konfigurations-Konflikte: Ticket nicht im aktuellen Auth-Kontext buchbar, Tour ohne passende Sprache
Reaktion hängt vom Sub-Fall ab:
- Pflichtfelder fehlen → Frontend-Validierung nachbessern, kein Retry
- Slot ausgebucht → Verfügbarkeit neu abfragen, User um Auswahl bitten, kein blinder Retry
- Reservation abgelaufen → neue Reservation anlegen
- Race-Condition (zwei parallele Order-Creates auf denselben Slot) → mit kleiner Verzögerung einmal retryen, dann aufgeben
404 - Resource fehlt
{ "error": "invalid route" }
oder
{ "error": "customer not found" }
Klassiker:
- Numerische ID, die es nicht gibt (oder die archiviert wurde)
- Token in URL, der nie existierte oder schon weg ist (
reservation_token) - Tippfehler in der Route
Reaktion: nicht retryen. Auf der UI passend "nicht gefunden" anzeigen.
410 - Resource ist weg
Selten, aber bei documents/:id/download (siehe Documents-Endpoint) und ähnlichen kommt es vor: das Dokument ist auf dem Server gewesen, ist aber inzwischen außer Reichweite (z.B. Aufbewahrungsfrist überschritten). Reaktion: nicht retryen, dem User sagen "nicht mehr verfügbar".
5xx - Serverseitiger Fehler
Wenn die go~mus-Instance kurz nicht antwortet (Deployment, Datenbank-Hick), erhältst du 502/503/504. Reaktion: exponential Backoff, 3-5 Versuche, danach Error-State im UI. Bei nicht-idempotenten Calls (POST Order, POST Reservation) Vorsicht beim Retry - der Server kann den Call schon empfangen und verarbeitet haben.
Idempotenz und Retry
Eine Faustregel:
| HTTP-Methode | Retry-sicher? |
|---|---|
GET, HEAD, OPTIONS | Ja |
PUT, DELETE | Ja |
POST | Nein, ohne extra Schutz |
Das heißt für POST /orders, POST /reservations, POST /requests:
- Auf Client-Seite den Erfolg eindeutig erkennen:
200/201mit gültigem Response-Body, sonst nicht erneut absenden. - Bei Timeout vor Retry erst prüfen: Bei Order und Request gibt es Listen-Endpoints (
GET /orders,GET /requests), in denen der Eintrag zu finden ist, falls der Server ihn doch angelegt hat. Bei Reservation gibt es kein Lookup - im Zweifel den vorherigen Token verfallen lassen und neu anlegen. - Foreign IDs nutzen: Wenn du Customers oder Orders mit deinem eigenen System synchronisieren, nutzt du
foreign_idals externen Schlüssel - dann kann der Server bei Wiederholungen den Duplikat erkennen, oder du in deinem System.
Mehr dazu in Best Practices.
Was du loggst sollten
Pro fehlgeschlagenem Call mindestens:
- HTTP-Status, vollständiger URL-Pfad mit Query-Params (Token-Werte maskiert)
- Body-Auszug aus dem Response (
errorunderrors-Array) - Zeitstempel (UTC) und Korrelations-ID, falls du eine setzen
- Letzte 4 Zeichen des verwendeten Bearer-Tokens (zur Identifikation, ohne Secret zu exponieren)
Das macht dir und uns das Debugging im Support-Fall um Größenordnungen einfacher.
Verwandte Seiten
- Authentifizierung - Token-Typen, Kontextsensitivität
- Best Practices - Caching, Idempotenz, Logging
- Konzepte - Order-Lebenszyklus, Reservation, Permissions