Fehlerbehandlung
REST und GraphQL verwenden unterschiedliche Fehlerformate:
- REST-Endpoints folgen den RFC 9457 Problem-Details und liefern den passenden Non-2xx-HTTP-Statuscode zurück.
- GraphQL-Abfrage-, Validierungs- und Laufzeitfehler werden im nativen GraphQL-Antwortformat
data+errorszurückgegeben (typischerweise HTTP200 OK).
REST-Fehlerantwortformat
REST-Fehlerantworten folgen dieser Struktur:
{
"type": "https://problems.tourfold.com/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "One or more fields failed validation",
"errors": [
{
"type": "https://problems.tourfold.com/field-size-invalid",
"title": "Field size invalid",
"detail": "The 'title' field exceeds the maximum length of 20 characters",
"pointer": "#/title",
"data": {
"max_length": 20
}
},
{
"type": "https://problems.tourfold.com/invalid-email",
"title": "Invalid email format",
"detail": "The email address format is invalid",
"pointer": "#/driver/email"
}
],
"data": {
"error_count": 2
}
}
Antwortfelder
Felder auf oberster Ebene
| Feld | Typ | Pflicht | Beschreibung | Beispiel |
|---|---|---|---|---|
type | string | Ja | Maschinenlesbare URI des Fehlertyps | "https://problems.tourfold.com/validation-failed" |
title | string | Ja | Menschenlesbare Fehlerzusammenfassung | "Validation failed" |
status | integer | Ja | HTTP-Statuscode | 422 |
detail | string | Ja | Ausführliche Fehlerbeschreibung | "One or more fields failed validation" |
errors | array | Nein | Fehlerdetails auf Feldebene | (siehe unten) |
data | object | Nein | Zusätzliche Kontextdaten | {"timestamp": "2024-01-15T10:30:00Z"} |
Felder im errors-Array
Jeder Eintrag im errors-Array enthält:
| Feld | Typ | Pflicht | Beschreibung | Beispiel |
|---|---|---|---|---|
type | string | Nein | Maschinenlesbarer Fehlertyp auf Feldebene | "https://problems.tourfold.com/field-required" |
detail | string | Ja | Feldspezifische Fehlerbeschreibung | "The 'name' field is required" |
pointer | string | Nein | JSON-Pointer auf das Feld | "#/name" |
data | object | Nein | Feldspezifische Zusatzdaten | {"provided_value": "invalid-email"} |
HTTP-Statuscodes
Der Statuscode sagt Ihnen, wo eine Anfrage fehlgeschlagen ist; type und errors[] sagen Ihnen, was.
| Status | Bedeutung | Wann |
|---|---|---|
400 Bad Request | Die Anfrage konnte nicht geparst werden. | Fehlerhaftes JSON, ein abgeschnittener Body, eine syntaktisch ungültige Anfrage — der Server hat nie eine wohlgeformte Anfrage erhalten, auf die er reagieren könnte. Problemtyp invalid-input. |
402 Payment Required | Der Workspace ist aufgrund der Abrechnung gesperrt. | Beheben Sie die Abrechnung über eine ausgenommene Billing-Recovery-Operation und wiederholen Sie danach die Anfrage. Problemtyp tenant-billing-locked. |
422 Unprocessable Content | Die Anfrage war wohlgeformt, wurde aber abgelehnt. | Jeder Validierungsfehler bei einer lesbaren Anfrage: ein Feld mit falschem Typ oder falscher Struktur (z. B. 1.5 für ein Integer-Feld, ein String, wo eine Zahl erwartet wird), ein fehlendes Pflichtfeld, ein Wert, der eine Einschränkung verletzt (Länge, Bereich, Format), oder eine Geschäftsregel, die die Anfrage ablehnt. Problemtyp validation-failed, mit errors[], das jedes betroffene Feld über pointer benennt. |
401 Unauthorized | Die Anfrage enthielt keine verwendbare Identität. | Überhaupt kein Authorization-Header, oder ein Token, das abgelaufen, fehlerhaft oder von einem nicht vertrauenswürdigen Issuer ausgestellt ist. Problemtyp authentication-required; data.reason ist token_missing, token_expired oder token_invalid, und die Antwort enthält einen WWW-Authenticate-Header. Nur token_expired rechtfertigt ein automatisches Erneuern und Wiederholen. |
403 Forbidden | Der Aufrufer ist authentifiziert, aber nicht berechtigt. | Die Identität ist bekannt, ihr fehlt aber ein erforderlicher Grant, sie ist nicht Eigentümer bzw. Ersteller der Ressource, oder der Plan des Workspace enthält die Funktion nicht. Problemtyp access-denied (oder ein spezifischerer, feature-bezogener Typ); data.reason benennt die Ursache und data.required_grants listet die erfüllenden Grants, wenn die Ablehnung grant-basiert ist. Eine Wiederholung mit derselben Identität hilft nicht. |
404 Not Found | Die adressierte Ressource existiert nicht. | |
405 Method Not Allowed | Der Pfad existiert, unterstützt aber nicht die angeforderte HTTP-Methode. | Verwenden Sie eine Methode aus dem Allow-Antwortheader. Problemtyp method-not-allowed; data.method enthält die abgelehnte Methode und data.supported die unterstützten Methoden. |
406 Not Acceptable | Der Endpoint kann keine vom Client akzeptierte Darstellung erzeugen. | Senden Sie einen vom Endpoint unterstützten Accept-Header. Problemtyp not-acceptable. |
409 Conflict | Die Anfrage steht im Konflikt mit dem aktuellen Zustand — z. B. eine Diskrepanz der optimistischen Sperrversion lock_version (resource-conflict). | |
410 Gone | Die zugrunde liegenden Daten einer bekannten Ressource sind dauerhaft nicht verfügbar. | Wiederholen Sie die Anfrage nicht unverändert. Der genaue feature-spezifische Typ erklärt, was nicht mehr verfügbar ist. |
413 Content Too Large | Die Anfrage überschreitet das für die Operation dokumentierte Payload-Limit. | Verkleinern Sie die Anfrage. Problemtyp payload-too-large. |
415 Unsupported Media Type | Der Request-Body verwendet einen Medientyp, den der Endpoint nicht akzeptiert. | Senden Sie einen in der Operation deklarierten Content-Type, normalerweise application/json. Problemtyp unsupported-media-type; data.content_type enthält den abgelehnten Wert und data.supported die akzeptierten Medientypen. |
429 Too Many Requests | Der Client wurde durch Ratenbegrenzung gedrosselt. | |
503 Service Unavailable | Ein benötigter Upstream-Service ist vorübergehend nicht verfügbar. | Wiederholen Sie die Anfrage entsprechend den Hinweisen der jeweiligen Operation. |
Faustregel — 400 vs. 422: Wenn wir Ihre Bytes nicht in eine Anfrage umwandeln konnten, ist es ein 400; wenn wir die Anfrage verstanden haben, sie aber nicht ausführen, ist es ein 422. Ein Feld mit falschem Typ oder ein fehlendes Feld ist immer ein 422 mit einem pointer (kein 400) — nur ein Body, den wir überhaupt nicht parsen können, ist ein 400. Dieselbe Regel gilt für Query- und Pfadparameter: ein Wert, den wir nicht in den erwarteten Typ umwandeln können, ist ein 422, benannt nach dem Parameternamen.
Auth-Fehler-Envelope (401 / 403)
401-Antworten vom Typ authentication-required und autorisierungsbedingte 403-Antworten
verwenden denselben Envelope: neben den üblichen Feldern type / title / status / detail
enthält das Problemdokument ein maschinenlesbares data.reason, sodass Clients nie den
detail-Text auswerten müssen, um das weitere Vorgehen zu bestimmen. Behandeln Sie data als
optional und prüfen Sie die Existenz, bevor Sie darauf zugreifen.
401 — authentication-required. data.reason ist genau einer dieser Werte:
token_missing— es wurden keine Anmeldedaten übermittelt. Authentifizieren.token_expired— ein wohlgeformtes, abgelaufenes Token. Access-Token erneuern und einmal wiederholen.token_invalid— fehlerhaftes Token, ungültige Signatur oder nicht vertrauenswürdiger Issuer. Keinen blinden Retry ausführen.
Die Antwort enthält außerdem einen WWW-Authenticate-Header: mit den Parametern nach
RFC 6750
(Bearer error="invalid_token", error_description="..."),
wenn ein Token übermittelt und abgelehnt wurde, oder als einfaches
Bearer, wenn keines gesendet wurde. login-failed ist der einzige weitere Problemtyp, der zu 401
führt; er deckt einen abgelehnten Login mit Anmeldedaten ab, nicht ein unbrauchbares Bearer-Token.
403 — access-denied. data.reason ist genau einer dieser Werte:
missing_grant— dem Aufrufer fehlt ein für die Operation erforderlicher Grant.not_owner/not_author/not_member— die Beziehung des Aufrufers zur Ressource passt nicht.plan_restricted— der Plan bzw. die Feature-Flags des Workspace enthalten die Funktion nicht.tenant_scope— die Ressource gehört zu einem anderen Workspace als dem des Aufrufers.resource_locked— der Zustand der Ressource verbietet die Aktion für alle.
data.required_grants listet die durch Doppelpunkte getrennten Grants auf, die die Prüfung erfüllt
hätten, z. B. ["users:update"]. Das Feld erscheint nur, wenn die Ablehnung grant-basiert ist und
die erforderlichen Grants statisch bekannt sind — Clients müssen es deshalb als optional behandeln.
Ein Feature kann anstelle von access-denied auch einen spezifischeren, namensraumbezogenen Typ
zurückgeben — zum Beispiel https://problems.tourfold.com/comments/cannot-edit-others — und behält
dabei denselben Status und dasselbe data.reason.
Ein typspezifischer 403-Fehler kann ein eigenes Ursachen-Vokabular definieren. Ein deaktivierter
Workspace liefert insbesondere https://problems.tourfold.com/tenant-disabled mit
data.reason = TENANT_INACTIVE. Prüfen Sie zuerst type, bevor Sie typspezifische data-Felder
auswerten; die geschlossene Liste oben gilt für Autorisierungsablehnungen.
Die vollständigen Payloads, die Details zum WWW-Authenticate-Header und die Regeln zur
Token-Erneuerung finden Sie unter
REST-Authentifizierung.
Fehler in OpenAPI-Operationen
Die OpenAPI-Beschreibung kombiniert Fehler auf Protokollebene mit Fehlern, die nur bei bestimmten Operationen auftreten:
- Abgesicherte Operationen dokumentieren
401. Operationen mit einer Antwortdarstellung dokumentieren406; Operationen mit Request-Body dokumentieren400und415. 405wird hier statt bei jeder Operation dokumentiert, weil der Status eine HTTP-Methode beschreibt, die für den Pfad gerade keine Operation ist.- Kontextabhängige Fehler wie
403,404,409,422,429und503erscheinen nur bei Operationen, die sie tatsächlich liefern können. Die Beschreibung nennt die jeweilige Bedingung und, sofern stabil, die URI des Problemtyps. 429und503sind keine allgemeinen Standardantworten. Implementiert eine Operation kein Rate-Limit oder hängt sie nicht von einem entsprechend übersetzten, nicht verfügbaren Upstream-Service ab, fehlen diese Antworten bewusst.
Jede Fehlerantwort enthält zusätzlich x-tourfold-problem-types: ein Array mit den stabilen
type-URIs auf oberster Ebene, die für diese Operation und diesen Status erwartet werden. Die
menschenlesbare Beschreibung nennt dieselben vollständigen URIs. Die Erweiterung beschreibt nur
das Problem auf oberster Ebene; Validierungs-Unterprobleme in errors[] verwenden das
Standardvokabular der Fehlertypen-Referenz oder von der Operation beschriebene feature-spezifische
Typen.
Diese Liste ist ein kuratierter öffentlicher Vertrag und kein vollständiger Dump aller internen
Exceptions. Sie enthält erwartete, behandelbare Fehler. Ein unerwarteter Serverfehler kann trotzdem
einen unbekannten Problemtyp liefern, auch wenn die Operation keinen generischen 500 bewirbt;
Clients benötigen daher immer einen Fallback für unbekannte Typen. Ein neuer Typ ist eine additive
Erweiterung. Die Bedeutung oder den Status eines bestehenden Typs zu ändern erfordert eine neue
API-Version.
Clients sollten anhand des HTTP-Status und der stabilen type-URI entscheiden, nicht anhand des
veränderlichen, menschenlesbaren detail-Texts.
Fehlertyp-System
Alle URIs der Fehlertypen sind dereferenzierbar. Öffnen Sie eine beliebige Problem-URI im Browser, um ihre Dokumentation anzuzeigen. Die URIs verweisen auf den Katalog der Fehlertypen.
Beispiele:
https://problems.tourfold.com/validation-failed– Häufige Validierungsfehlerhttps://problems.tourfold.com/not-found– Ressource nicht gefundenhttps://problems.tourfold.com/tours/tour-ended– Tour-spezifische Fehlerhttps://problems.tourfold.com/cases/case-already-assigned– Vorgangsspezifische Fehler
Ausprobieren
Fügen Sie eine Problem-URI in Ihren Browser ein, um sofort die Dokumentation zu sehen:
Vollständiger Katalog
Alle Fehlertypen und Beschreibungen finden Sie in der Fehlertypen-Referenz.
JSON-Pointer-Syntax
Wir verwenden die JSON-Pointer-Syntax, um konkrete Felder zu identifizieren:
#/name– Feld auf oberster Ebene#/contact/email– Feld in einem verschachtelten Objekt#/drivers/0/email– Element eines Arrays#/settings/notifications/0/channels/1– Tief verschachteltes Array-Element
Unterstützung für Internationalisierung
Unsere API-Antworten sind zwar auf Englisch, das strukturierte Fehlerformat erlaubt Anwendungen jedoch, lokalisierte Fehlermeldungen anzuzeigen. Frontends sollten die type-URI als Übersetzungsschlüssel verwenden.
GraphQL-Fehlerantworten
- Der HTTP-Status ist üblicherweise
200 OK; Abfrage-, Validierungs- und Laufzeitfehler werden imerrors-Array gemeldet. - GraphQL-Fehler verwenden nicht den RFC-9457-Problem-Umschlag (
type,title,detail,status). - Transport-Fehler (zum Beispiel bei der Authentifizierung) können weiterhin Non-200-HTTP-Statuscodes zurückgeben, bevor GraphQL überhaupt ausgeführt wird.
GraphQL-Antwortstruktur
| Feld | Typ | Beschreibung |
|---|---|---|
data | object, null oder nicht vorhanden | Abfrageergebnis. Teilweise, wenn ein nullable Feld gescheitert ist; null, wenn ein non-null Wurzelfeld gescheitert ist; vollständig nicht vorhanden, wenn das Dokument nicht geparst oder validiert werden konnte — dann wurde nichts ausgeführt. |
errors | array | Liste der GraphQL-Fehler |
Jeder Eintrag in errors enthält typischerweise:
| Feld | Typ | Beschreibung |
|---|---|---|
message | string | Menschenlesbare GraphQL-Fehlermeldung |
locations | array | Quellpositionen (line, column) im GraphQL-Dokument |
path | array oder null | Resolver-Pfad (bei Validierungsfehlern oft null) |
GraphQL-Beispiel
{
"data": null,
"errors": [
{
"message": "Validation error (WrongType@[product]) : argument 'order_by[0].price' with value 'EnumValue{name='invalid_direction'}' is not a valid 'SortDirection' - Literal value not in allowable values for enum 'SortDirection' - 'EnumValue{name='invalid_direction'}'",
"locations": [{ "line": 1, "column": 11 }],
"path": null
},
{
"message": "Validation error (FieldUndefined@[vending_machine/cpu_processor]) : Field 'cpu_processor' in type 'vending_machine' is undefined",
"locations": [{ "line": 5, "column": 9 }],
"path": null
},
{
"message": "Validation error (FieldUndefined@[vending_machine/manufacturer/founding_year]) : Field 'founding_year' in type 'manufacturer' is undefined",
"locations": [{ "line": 8, "column": 13 }],
"path": null
}
]
}
Nächste Schritte
- Lernen Sie mehr über
REST-Authentifizierung - Verstehen Sie
GraphQL-Auth - Entdecken Sie
Paginierung und Filterung - Sehen Sie die
Fehlertypen-Referenzan