feathermost/ajax.js

102 lines
2.6 KiB
JavaScript

const ajax = (function() { "use strict";
class AjaxError extends Error {
constructor (message, response, ...rest) {
super(message, ...rest);
this.response = response;
}
}
class NetworkError extends AjaxError {}
class NotOkError extends AjaxError {}
class UnexpectedMimeError extends AjaxError {}
class InvalidJsonError extends AjaxError {}
const MIME_JSON = "application/json";
/**
* Wrap a function so that it receives `this` as first argument.
*/
function thisToArg(f) {
return function(...rest) {
return f(this, ...rest);
}
}
function xhrInitForPromise(resolve, reject, url, method, headers) {
const t_resolve = thisToArg(resolve),
t_reject = thisToArg(reject);
let xhr = new XMLHttpRequest();
xhr.addEventListener("load", t_resolve);
xhr.addEventListener("error", t_resolve);
xhr.addEventListener("abort", t_reject);
xhr.addEventListener("timeout", t_reject);
xhr.open(method, url);
for (let header of Object.getOwnPropertyNames(headers)) {
xhr.setRequestHeader(header, headers[header]);
}
return xhr;
}
function xhrParseJsonResponse(xhr) {
xhr.responseJson = null;
xhr.ok = false;
if (xhr.responseText) {
const contentType = xhr.getResponseHeader("Content-Type");
if (contentType != MIME_JSON) {
throw new UnexpectedMimeError(`Server did not reply with JSON but with ${contentType}`, xhr);
}
try {
xhr.responseJson = JSON.parse(xhr.responseText);
} catch(e) {
throw new InvalidJsonError("Server replied with JSON that we couldn't parse", xhr);
}
}
xhr.ok = 200 <= xhr.status && xhr.status < 300;
if (!xhr.ok) {
console.error(xhr);
if (xhr.status === 0) {
throw new NetworkError("Failed to connect to server. Developer console may have more information", xhr);
} else {
throw new NotOkError(xhr.statusText, xhr);
}
}
return xhr;
}
function getJson(url, options={}) {
if (!options.headers) options.headers = {};
options.headers["Accept"] = MIME_JSON;
return new Promise((resolve, reject) => {
let xhr = xhrInitForPromise(resolve, reject, url, "GET", options.headers);
xhr.send();
}).then(xhrParseJsonResponse);
}
function postJson(url, data=undefined, options={}) {
if (!options.headers) options.headers = {};
options.headers["Content-Type"] = MIME_JSON;
options.headers["Accept"] = MIME_JSON;
return new Promise((resolve, reject) => {
let xhr = xhrInitForPromise(resolve, reject, url, "POST", options.headers);
if (data === undefined) {
xhr.send();
} else {
xhr.send(JSON.stringify(data));
}
}).then(xhrParseJsonResponse);
}
return {
NetworkError, NotOkError, UnexpectedMimeError, InvalidJsonError,
getJson, postJson
};
})();