- Enhanced the `formatApiError` function to better format failed API responses, preventing raw HTML error pages from being displayed in toasts. JSON error bodies are now prioritized for user-friendly messages, while HTML and empty bodies are collapsed to a concise status line. Long plain-text bodies are truncated for readability.
- Updated tests to cover new error formatting behavior, ensuring accurate extraction of error messages from various JSON structures.
Failed API responses whose body is not JSON - Django's HTML "Server
Error (500)" page, nginx's HTML 502/504 pages when the backend is down
or timing out - were interpolated verbatim into the error toast,
showing users a wall of markup.
request() deliberately keeps the raw text when JSON.parse fails, and
errorNotification() rendered `${status} - ${body}` unconditionally.
Route the body through a new formatApiError() helper (in utils.js so it
is unit-testable without importing the store-heavy api module):
- JSON object bodies keep their existing pretty-printed formatting
- markup and empty bodies collapse to the response's own status line:
the declared Content-Type decides what counts as markup (body
sniffing only as fallback when the header is missing), and the label
comes from the fetch Response's statusText - the protocol's reason
phrase, defined for every status code, rather than a hardcoded status
map. HTTP/2+ transmits no reason phrase, so an empty statusText falls
back to a generic label. request() already attaches the Response to
the error, so no call-site changes are needed.
- the full suppressed body goes to console.debug so the markup stays
available for troubleshooting (deliberate, not a leftover debug
statement)
- plain-text bodies are truncated at 200 chars as a backstop
- errors without a status keep the error.message fallback