diff --git a/docs/api/error-handling.md b/docs/api/error-handling.md index f4c8c1cd..609f61e9 100644 --- a/docs/api/error-handling.md +++ b/docs/api/error-handling.md @@ -284,6 +284,33 @@ async def invalid_token_handler(request, exc): ) ``` +## Frontend Error Handling (apiClient) + +When a request fails, the shared `apiClient` (`static/shared/js/api-client.js`) throws an `Error` with three structured properties populated from the JSON response, in addition to the `message`: + +| Property | Source | Example | +|----------|--------|---------| +| `error.status` | HTTP status code | `429` | +| `error.errorCode` | Server `error_code` field | `"POINTS_COOLDOWN"` | +| `error.details` | Server `details` object (may be `null`) | `{ cooldown_minutes: 5, cooldown_ends: "..." }` | + +This lets callers branch on a machine-readable code and localise the toast instead of rendering the raw English `message`. Pattern: + +```js +try { + await apiClient.post('/store/loyalty/transactions', payload); +} catch (error) { + if (error.errorCode === 'POINTS_COOLDOWN' || error.errorCode === 'STAMP_COOLDOWN') { + const minutes = error.details?.cooldown_minutes ?? ''; + Utils.showToast(I18n.t('loyalty.store.terminal.cooldown_wait_minutes', { minutes }), 'warning'); + } else { + Utils.showToast(I18n.t('loyalty.store.terminal.transaction_failed', { message: error.message }), 'error'); + } +} +``` + +Generic FastAPI errors that don't carry `error_code` / `details` will leave those properties `undefined` / `null`, so a `?.` chain is the right guard. + ## Related Documentation - [Authentication](authentication.md) - Authentication-related exceptions