93 lines
2.3 KiB
JavaScript
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
|
|
};
|
|
|
|
})();
|