Error class for non-ok HTTP responses from the Fetch API. Captures the response body as text and JSON for debugging.
$ npm install @stores.com/http-error
const HttpError = require('@stores.com/http-error');
const response = await fetch('https://api.example.com/items');
if (!response.ok) {
throw await HttpError.from(response);
}Catching errors:
try {
const response = await fetch('https://api.example.com/items');
if (!response.ok) {
throw await HttpError.from(response);
}
} catch (err) {
console.error(err.message); // "404 Not Found" — or aggregated body errors[].message values
console.error(err.text); // Raw response body
console.error(err.json); // Parsed JSON (if applicable)
console.error(err.cause); // Original Response object
}Some APIs carry application-level failures in the response body rather than (or in addition to) HTTP status codes. from() reads the body and aggregates an errors[] envelope into the message automatically — for each entry, the first present of message or detail is used, joined by ; . Codes and any other per-error fields stay on err.json.errors[].
const response = await fetch('https://api.example.com/graphql', { /* ... */ });
if (!response.ok) {
throw await HttpError.from(response);
}
const json = await response.json();
if (json?.errors?.length) {
throw await HttpError.from(response, json);
}
return json;Pass just the Response while its body is still unread (the non-ok case). Once you've read it with response.json(), pass that parsed body as the second argument — from(response, json) — so it isn't re-read (a response body can only be read once). Either way the error keeps the response status and cause.
The default "${status} ${statusText}" message is used when the body has no errors[].
This covers two widely used envelope shapes:
- GraphQL — every response error entry includes a
messagestring. Servers return 200 OK with a top-levelerrors[]for both partial and total failures. The same envelope is used by many REST APIs that signal application-level failures in the body rather than (or in addition to) HTTP status codes. - JSON:API — error objects use
detailfor the per-occurrence explanation.
Creates an error with message "${status} ${statusText}" and sets cause to the response.
Async factory that creates an HttpError from a Response and captures the body:
- With just a
Response, the body is read viaresponse.clone()(the original is not consumed) and captured aserr.textanderr.json. - With an already-parsed
jsonas the second argument, that body is used directly (the response is not read), witherr.textset to its JSON string — for a 200 response whose JSON you've already read.
In both cases:
err.text— the body as a stringerr.json— the parsed JSON (if the body is/was valid JSON)err.cause— the originalResponse
If the body carries an errors[] array, err.message is set to each entry's message or detail (whichever is present, in that order) joined by ; instead of the default "${status} ${statusText}". See APIs that return errors in the body above.