feathermost/ajax.js

102 lines
2.6 KiB
JavaScript
Raw Normal View History

2020-03-25 17:05:25 +01:00
const ajax = (function() { "use strict";
2020-03-26 16:01:09 +01:00
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 {}
2020-03-25 17:05:25 +01:00
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) {
2020-03-26 16:01:09 +01:00
xhr.responseJson = null;
xhr.ok = false;
2020-03-25 17:05:25 +01:00
2020-03-26 16:01:09 +01:00
if (xhr.responseText) {
2020-03-25 17:05:25 +01:00
const contentType = xhr.getResponseHeader("Content-Type");
if (contentType != MIME_JSON) {
2020-03-26 16:01:09 +01:00
throw new UnexpectedMimeError(`Server did not reply with JSON but with ${contentType}`, xhr);
2020-03-25 17:05:25 +01:00
}
try {
2020-03-26 16:01:09 +01:00
xhr.responseJson = JSON.parse(xhr.responseText);
2020-03-25 17:05:25 +01:00
} catch(e) {
2020-03-26 16:01:09 +01:00
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);
2020-03-25 17:05:25 +01:00
}
}
2020-03-26 16:01:09 +01:00
return xhr;
2020-03-25 17:05:25 +01:00
}
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);
}
2020-03-26 16:01:09 +01:00
function postJson(url, data=undefined, options={}) {
2020-03-25 17:05:25 +01:00
if (!options.headers) options.headers = {};
options.headers["Content-Type"] = MIME_JSON;
options.headers["Accept"] = MIME_JSON;
2020-03-25 17:05:25 +01:00
return new Promise((resolve, reject) => {
let xhr = xhrInitForPromise(resolve, reject, url, "POST", options.headers);
2020-03-26 16:01:09 +01:00
if (data === undefined) {
xhr.send();
} else {
xhr.send(JSON.stringify(data));
}
2020-03-25 17:05:25 +01:00
}).then(xhrParseJsonResponse);
}
return {
2020-03-26 16:01:09 +01:00
NetworkError, NotOkError, UnexpectedMimeError, InvalidJsonError,
2020-03-25 17:05:25 +01:00
getJson, postJson
};
})();