Chyby GraphQL API: errors a errorDetails
Výsledek mutace nebo dotazu, který má pole errors, nabízí vedle něj volitelné pole
errorDetails se strojově čitelným popisem týchž chyb: stabilní kód, kategorie, vstupní pole
a parametry. Seznam kódů, jejich kategorie a pravidla stability
jsou v katalogu kódů chyb.
Ukázky JSON níže jsou v dekódovaném tvaru. Server odpovídá odsazeným JSON a uvozovky a znaky
mimo ASCII uvnitř řetězců posílá jako \uXXXX — na tom se nic nemění.
Pole errors se nemění
errorszůstává seznam řetězců se stejnými texty, ve stejném pořadí a stejném počtu, při úspěchu[]. Klient, kterýerrorDetailsnevybírá, dostává odpověď beze změny bajt po bajtu.- Jediný rozdíl, který může vidět i dosavadní klient: text chyby GraphQL o neznámém poli ve výsledku
(
Field "erors" not found in type "createProduct". Available fields are: …) vyjmenovává všechna pole výsledku, tedy nově i"errorDetails". Týká se jen dokumentu, který už tak selhává. errorDetailsje jen u výsledků, které majíerrors(unextCodeanextEanje vždy[]). Seznamové dotazy bezerrorsa chyby na nejvyšší úrovni odpovědi ho nemají.
Tvar errorDetails
errorDetails { code category message text field params { name value } }
Položka i vysvětluje errors[i]: seznamy mají vždy stejný počet položek ve stejném pořadí
a message je přesně řetězec errors[i]. errorDetails je [] právě tehdy, když errors je [].
| Pole | Význam |
|---|---|
code |
Stabilní kód chyby, např. NOT_FOUND. UNCLASSIFIED = chyba zatím bez kódu, zpracujte ji podle textu jako dosud. |
category |
Kategorie odvozená z kódu (validation, auth, retry, outcome_unknown, …) — obecné rozhodnutí, co s chybou dělat. |
message |
Přesně text errors[i]. |
text |
Text chyby bez dosavadních ozdob (předpona pole: , příčina nebo cesta v závorce); u některých kódů srozumitelnější věta, např. u NOT_DELETABLE „Záznam nelze smazat, protože se stále používá.“. |
field |
Cesta ke vstupní hodnotě tak, jak ji píše text chyby (ean, items[0].product); null u chyby, která se netýká jednoho pole. |
params |
Podrobnosti jako dvojice name/value; hodnoty jsou vždy řetězce. [], když žádné nejsou. |
Všechna pole jsou v GraphQL schématu nullable. Kterýkoli parametr může u konkrétní chyby chybět.
Příklad — úprava neexistující objednávky:
{
"data": {
"updateOrder": {
"data": null,
"errors": ["Error 404: Not found."],
"errorDetails": [
{
"code": "NOT_FOUND",
"category": "not_found",
"message": "Error 404: Not found.",
"text": "Error 404: Not found.",
"field": null,
"params": []
}
]
}
}
}
Chyba, kterou server zatím neklasifikuje, přijde s kódem UNCLASSIFIED a kategorií unknown;
message i text jsou dosavadní text:
"errors": ["Text chyby."],
"errorDetails": [
{
"code": "UNCLASSIFIED",
"category": "unknown",
"message": "Text chyby.",
"text": "Text chyby.",
"field": null,
"params": []
}
]
Až chyba dostane kód, změní se jen code, category, případně text, field a params —
např. úprava zrušené objednávky:
"errors": ["Objednávka je zrušená, nelze ji upravovat."],
"errorDetails": [
{
"code": "ORDER_CANCELLED",
"category": "business",
"message": "Objednávka je zrušená, nelze ji upravovat.",
"text": "Objednávka je zrušená, nelze ji upravovat.",
"field": null,
"params": [{ "name": "order", "value": "4711" }]
}
]
Příklad — založení produktu s EAN, který už má jiný produkt, a s neexistujícím výrobcem. Chyby
kontroly hodnot mají v field vstupní pole, v text hlášku bez předpony pole: a v params
hodnotu, kterou text cituje:
"errors": [
"ean: Produkt se stejným eanem: \"8590000000001\" už existuje.",
"producer: Vybraná možnost není platná."
],
"errorDetails": [
{
"code": "VALUE_NOT_UNIQUE",
"category": "validation",
"message": "ean: Produkt se stejným eanem: \"8590000000001\" už existuje.",
"text": "Produkt se stejným eanem: \"8590000000001\" už existuje.",
"field": "ean",
"params": [{ "name": "value", "value": "8590000000001" }]
},
{
"code": "VALUE_INVALID",
"category": "validation",
"message": "producer: Vybraná možnost není platná.",
"text": "Vybraná možnost není platná.",
"field": "producer",
"params": []
}
]
Stejný text může mít různé kódy: Error 403: Forbidden. u mazání znamená FORBIDDEN (entita
patří jiné firmě), nebo NOT_DELETABLE (záznam nelze smazat — na entitu odkazují jiné záznamy,
nebo by smazání skladového pohybu odebralo víc kusů, než je na skladě; důvod uvádí text).
Rozhodujte podle kódu.
Kódy chyb jednotlivých oblastí uvádí i jejich dokumentace, např. sady a volba konkrétních productDepots u položky objednávky.
Objednávky (createOrder, updateOrder, cancelReservation, deleteReservation) mají kódy
u všech svých chyb, např. ORDER_CANCELLED, ORDER_BILLED_ITEM_NOT_REMOVABLE,
ORDER_PROCESS_STATUS_CHANGE_FORBIDDEN, při vyskladnění STOCK_INSUFFICIENT (s product,
productDepot, requested, available) a ORDER_DISPATCH_QUANTITY_MISMATCH. Vyskladnění,
které narazí na rezervaci změněnou souběžným požadavkem, má OPERATION_IN_PROGRESS: nic se
nezapsalo a požadavek lze poslat znovu. Výpis kontroly položky nebo formuláře v jedné chybě má
kód podle chyby, je-li jediná (field např. items[0].type), jinak VALIDATION_FAILED bez
field.
Produkty, sady, firmy a platby mají kódy u všech svých chyb: dotazy productPurchasePrice,
productSellPrice a productSellItems hlásí neexistující odkaz jako REFERENCE_NOT_FOUND
(field je argument, např. depots[0], id jeho hodnota) a odkaz mimo vaši firmu jako
FORBIDDEN s týmž field; změnu isBundle, která by zanechala zboží nebo rezervace, odmítá
BUNDLE_SWITCH_FORBIDDEN a sadu, která by obsahovala sama sebe, BUNDLE_CYCLE. Smazání firmy,
které selže, má COMPANY_DELETE_FAILED s kódem příčiny v cause.
Kódy mají i chyby ostatních částí API: chybějící nebo cizí záznam (NOT_FOUND, FORBIDDEN —
kategorie, štítky, kurzy měn, inventury, souhlasy zákazníků, profil uživatele; u
createCustomerConsent uvádí field, který z odkazů consent/customer se nenašel), odeslání
EET (EET_NOT_SUPPORTED), historie změn loggableHistory (MISSING_ARGUMENT /
INVALID_ARGUMENT s názvem argumentu ve field; historie entity jiné firmy FORBIDDEN, chyba
si přitom ponechává message „Access Denied.“ a číselný code 403), soubor inventury, který
není platný Excel XLSX (VALUE_INVALID_FORMAT), příliš velký export (EXPORT_TOO_LARGE
s count a limit) a typ exportu, který server neumí vytvořit (INTERNAL_ERROR).
Server doplňuje konkrétní kódy postupně; přechod chyby z UNCLASSIFIED na konkrétní kód ohlásí
v novinkách.
Vybírejte vždy všechna podpole
Používejte v klientu jednu konstantu s celým výběrem a vkládejte ji všude, kde vybíráte errors:
errorDetails { code category message text field params { name value } }
Výběr errorDetails bez podpolí ({ errors errorDetails }) server neodmítne, ale vrátí za
každou chybu prázdný seznam ("errorDetails": [[], []]), takže kódy nedostanete. Pozor na
generátory dotazů, které pole vykreslují jako holý název (errors: null → errors): stejný vzor
u errorDetails vede právě k tomuto výsledku. Server takový výběr zaznamená jako varování,
odpověď nemění.
code je řetězec, ne výčet
code je ve schématu String. Negenerujte z kódů GraphQL enum ani uzavřený výčet, který by
na neznámou hodnotu selhal: kódy průběžně přibývají. Kód, který klient nezná, zpracujte podle
category.
encodeOutput
Pro OAuth klienta s nastaveným encodeOutput je errorDetails zakódované stejně jako errors
téže odpovědi: message, text, field a hodnoty params jsou urlencoded právě tehdy, když je
urlencoded errors[i]; code, category a názvy parametrů se kódováním nemění. Například
"errors": ["Error+403%3A+Forbidden.+%28items%5B0%5D.vat%29"] má položku s "text": "Error+403%3A+Forbidden." a "field": "items%5B0%5D.vat". Dekódujte obě pole stejně.
Kdy smí klient errorDetails vybírat
Server, který errorDetails nezná (starší verze, jiný server, návrat k předchozí verzi), dokument
s tímto polem nejdřív provede a teprve potom odmítne výběr: mutace proběhne a uloží se, klient
ale dostane null a chybu (viz níže). Podporu proto
zjišťujte dřív, než errorDetails pošlete — nikdy zkusmo.
-
Server, který
errorDetailspodporuje, posílá na každé odpovědi/graphqls HTTP 200 (i s chybami) hlavičkuX-Depoto-Capabilities: error-detailsHodnota je seznam schopností oddělených čárkou; další mohou přibýt. Hledejte v něm token
error-details, neporovnávejte celou hodnotu. -
errorDetailsvybírejte, jen když poslední odpověď HTTP 200 z/graphqltéhož serveru (stejné adresy API) hlavičku s tokenem nesla. Odpověď HTTP 200 z/graphqlbez tokenu příznak okamžitě ruší. Odpovědi s jiným stavem (400, 401, 429, 5xx) příznak nemění. -
Pamatujte si příznak zvlášť pro každý server, se kterým klient mluví. Sdílená cache (napříč procesy) ho smí držet nejvýš 10 minut a každá odpověď ho obnovuje.
-
První dotaz na nový server pošlete bez
errorDetails(třeba jen dotaz, který stejně potřebujete). -
Prohlížeč hlavičku přečte, server ji pro
/graphqlzpřístupňuje vAccess-Control-Expose-Headers. -
Kdo hlavičky číst nemůže, najde stejný seznam v
GET /status/version:"capabilities": ["error-details"].
Chyba Field "errorDetails" not found
Když přesto přijde chyba na nejvyšší úrovni s textem začínajícím Field "errorDetails" not found in type, mluvíte se serverem bez podpory a výsledek operace je neznámý:
mutation { createOrder(…) { data { id } errors errorDetails { code } } }
{
"data": { "createOrder": null },
"errors": [
{
"message": "Field \"errorDetails\" not found in type \"createOrder\". Available fields are: \"data\", \"errors\"",
"locations": [{ "line": 1, "column": … }]
}
]
}
…a objednávka byla vytvořena.
- Mutaci nikdy automaticky neopakujte (ani bez
errorDetails): mohla proběhnout, opakování by zdvojilo doklad. Zrušte příznak podpory a předejte chybu volajícímu, aby si stav načetl znovu (stejně jako u kategorieoutcome_unknown). - Dotaz (
query) opakovat bezerrorDetailssmíte, nic nezapisuje. - Totéž platí pro neznámé kořenové pole: kořenová pole před ním už server provedl (mutace se
uloží) a odpověď nemá vůbec klíč
data. Do dokumentu s mutací proto nepřidávejte pole, o kterém nevíte, že ho server zná.
Kategorie outcome_unknown
Chyba s kategorií outcome_unknown (např. zablokování databáze nebo vypršení spojení s dopravcem)
znamená, že zápis mohl proběhnout. Před opakováním načtěte stav (objednávku, zásilku, pohyb),
jinak hrozí zdvojený doklad. Naproti tomu retry znamená, že se nic nezapsalo a požadavek lze
poslat znovu beze změny.
Dávkové požadavky
Tělo požadavku s polem JSON (dávka několika dokumentů) dostane pole odpovědí ve stejném pořadí.
Každá odpověď obsahuje v errors na nejvyšší úrovni jen chyby svého dokumentu; úspěšný dokument
klíč errors nemá. Dříve odpověď na pozdější dokument opakovala i chyby dokumentů před ním.
errors a errorDetails uvnitř výsledků se to netýká, ty byly vždy jen svého výsledku.
Chyby na nejvyšší úrovni (extensions)
Chyby v poli errors na nejvyšší úrovni odpovědi (např. Access Denied. nebo neplatný argument)
mohou nést stejný kód jako klíč extensions (code, category a podle potřeby field, params,
text) za dosavadními klíči message, code a locations, které se nemění. Server ho posílá
jen na požádání: u požadavků s hlavičkou X-Depoto-Error-Codes: 1, nebo trvale pro integraci,
které ho na žádost zapne podpora Depoto. Schopnost error-details se ke klíči extensions
nevztahuje.