61 lines
2.9 KiB
JavaScript
61 lines
2.9 KiB
JavaScript
/**
|
||
* Errors the API reports to clients: an HTTP status, a stable machine-readable `code` and a
|
||
* message ready to show. Clients branch on the code, never on the wording of the message.
|
||
*
|
||
* 400 bad_request the request itself is wrong (missing or malformed parameters)
|
||
* 404 unknown_endpoint no such API address: the server is older than the client
|
||
* 404 document_not_found the document left the catalog
|
||
* 404 group_not_found the document has no such group
|
||
* 413 file_too_large an import over 10 MB
|
||
* 422 unreadable_file an import that is not a readable Word table
|
||
* 429 too_many_requests the client sends too much; Retry-After says when to come back
|
||
* 429 busy the server is parsing other imports
|
||
* 502 source_unavailable the university catalog did not answer
|
||
* 502 source_invalid the catalog answered, but its folders or tables are not recognised
|
||
* 503 not_ready /api/ready only: the server is still loading the catalog or its index
|
||
* 504 source_timeout the university catalog answered too slowly
|
||
* 504 timeout the server did not answer within its time limit
|
||
* 500 internal a fault of the server itself
|
||
*/
|
||
export class ApiError extends Error {
|
||
constructor(status, code, message) {
|
||
super(message);
|
||
this.status = status;
|
||
this.code = code;
|
||
}
|
||
}
|
||
|
||
export const apiError = (status, code, message) => new ApiError(status, code, message);
|
||
|
||
const SOURCE_DOWN = "Каталог университета сейчас не отвечает. Попробуйте позже.";
|
||
const SOURCE_SLOW = "Каталог университета отвечает слишком долго. Попробуйте позже.";
|
||
|
||
/**
|
||
* A failed download from the university as an API error: fetch aborted on the time limit is a
|
||
* timeout, any other failure (no connection, an HTTP error, a redirect) means the source is unavailable.
|
||
*/
|
||
export function sourceError(error) {
|
||
if (error instanceof ApiError) return error;
|
||
const timedOut = error?.name === "TimeoutError" || error?.name === "AbortError";
|
||
return timedOut
|
||
? new ApiError(504, "source_timeout", SOURCE_SLOW)
|
||
: new ApiError(502, "source_unavailable", SOURCE_DOWN);
|
||
}
|
||
|
||
/** Status, code and message for any error that reached the error handler. */
|
||
export function describe(error) {
|
||
if (error instanceof ApiError)
|
||
return { status: error.status, code: error.code, message: error.message };
|
||
if (error?.code === "LIMIT_FILE_SIZE")
|
||
return {
|
||
status: 413,
|
||
code: "file_too_large",
|
||
message: "Файл больше 10 МБ. Выберите документ меньшего размера.",
|
||
};
|
||
return {
|
||
status: 500,
|
||
code: "internal",
|
||
message: "Не удалось загрузить расписание. Проверьте подключение и попробуйте ещё раз.",
|
||
};
|
||
}
|