feathermost/xhr.js

93 lines
2.3 KiB
JavaScript

const ajax = (function() { "use strict";
class NetworkError extends Error {}
class UnexpectedMimeError extends Error {}
class InvalidJsonError extends Error {}
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) {
if (xhr.status === 0) {
console.error(xhr);
throw new NetworkError("Failed to connect to server");
}
let json;
if (!xhr.responseText) {
json = null;
} else {
const contentType = xhr.getResponseHeader("Content-Type");
if (contentType != MIME_JSON) {
throw new UnexpectedMimeError(`Server did not reply with JSON but with ${contentType}`);
}
try {
json = JSON.parse(xhr.responseText);
} catch(e) {
throw new InvalidJsonError();
}
}
return {
ok: 200 <= xhr.status && xhr.status < 300,
status: xhr.status,
statusText: xhr.statusText,
getHeader: header => xhr.getResponseHeader(header),
json,
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={}, options={}) {
if (!options.headers) options.headers = {};
// This triggers CORS, which is not acceptable
//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);
xhr.send(JSON.stringify(data));
}).then(xhrParseJsonResponse);
}
return {
NetworkError, UnexpectedMimeError, InvalidJsonError,
getJson, postJson
};
})();