Add structured logging and better error handling
This commit is contained in:
1 parent
db4e3c9611
commit
68c7dd76f2
31 files changed
+640
-109
No files matched your search
+42
-5
@@ -1,8 +1,22 @@
|
||||
export class ApiError extends Error {
|
||||
constructor(status, message) {
|
||||
constructor(status, message, requestId = "") {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
get isNetworkError() {
|
||||
return this.status === 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function describeError(error) {
|
||||
const message = error && error.message ? error.message : "Something went wrong.";
|
||||
const alreadyReferenced = message.includes("reference");
|
||||
if (error instanceof ApiError && error.requestId && error.status >= 500 && !alreadyReferenced) {
|
||||
return `${message} (reference ${error.requestId})`;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
const unauthorizedListeners = new Set();
|
||||
@@ -20,6 +34,22 @@ function parseBody(text) {
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackMessage(status) {
|
||||
if (status === 502 || status === 503 || status === 504) {
|
||||
return `The server is not responding right now (${status}). Try again in a moment.`;
|
||||
}
|
||||
if (status === 413) return "The request was too large.";
|
||||
return `Request failed (${status}).`;
|
||||
}
|
||||
|
||||
async function send(path, options) {
|
||||
try {
|
||||
return await fetch(path, options);
|
||||
} catch {
|
||||
throw new ApiError(0, "Cannot reach the server. Check your connection.");
|
||||
}
|
||||
}
|
||||
|
||||
async function request(method, path, body) {
|
||||
const options = { method, credentials: "same-origin", headers: {} };
|
||||
if (body !== undefined) {
|
||||
@@ -27,15 +57,22 @@ async function request(method, path, body) {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const response = await fetch(path, options);
|
||||
const data = parseBody(await response.text());
|
||||
const response = await send(path, options);
|
||||
let text = "";
|
||||
try {
|
||||
text = await response.text();
|
||||
} catch {
|
||||
throw new ApiError(0, "The connection dropped while reading the server response.");
|
||||
}
|
||||
const data = parseBody(text);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401 && path !== "/api/login") {
|
||||
unauthorizedListeners.forEach((listener) => listener());
|
||||
}
|
||||
const message = data && data.error ? data.error : `Request failed (${response.status})`;
|
||||
throw new ApiError(response.status, message);
|
||||
const message = data && data.error ? data.error : fallbackMessage(response.status);
|
||||
const requestId = (data && data.requestId) || response.headers.get("X-Request-ID") || "";
|
||||
throw new ApiError(response.status, message, requestId);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user