wretch
Version:
A tiny wrapper built around fetch with an intuitive syntax.
85 lines • 3.62 kB
JavaScript
import { middlewareHelper } from "./middleware.js";
import { mix } from "./utils.js";
import { FETCH_ERROR } from "./constants.js";
/**
* This class inheriting from Error is thrown when the fetch response is not "ok".
* It extends Error and adds status, text and body fields.
*/
export class WretchError extends Error {
}
export const resolver = (wretch) => {
const { _url: url, _options: opts, _config: config, _catchers: _catchers, _resolvers: resolvers, _middlewares: middlewares, _addons: addons } = wretch;
const catchers = new Map(_catchers);
const finalOptions = mix(config.options, opts);
addons.forEach(addon => addon.beforeRequest && addon.beforeRequest(wretch, finalOptions));
// The generated fetch request
const _fetchReq = middlewareHelper(middlewares)(config.polyfill("fetch"))(url, finalOptions);
// Throws on an http error
const referenceError = new Error();
const throwingPromise = _fetchReq
.catch(error => {
throw { __wrap: error };
})
.then(response => {
if (!response.ok) {
const err = new WretchError();
// Enhance the error object
err["cause"] = referenceError;
err.stack = err.stack + "\nCAUSE: " + referenceError.stack;
err.response = response;
if (response.type === "opaque") {
throw err;
}
return response[config.errorType]().then((body) => {
err.message = body;
err[config.errorType] = body;
err["status"] = response.status;
throw err;
});
}
return response;
});
// Wraps the Promise in order to dispatch the error to a matching catcher
const catchersWrapper = (promise) => {
return promise.catch(err => {
const error = err.__wrap || err;
const catcher = err.__wrap && catchers.has(FETCH_ERROR) ? catchers.get(FETCH_ERROR) :
(catchers.get(error.status) || catchers.get(error.name));
if (catcher)
return catcher(error, wretch);
throw error;
});
};
const bodyParser = funName => cb => funName ?
// If a callback is provided, then callback with the body result otherwise return the parsed body itself.
catchersWrapper(throwingPromise.then(_ => _ && _[funName]()).then(_ => cb ? cb(_) : _)) :
// No body parsing method - return the response
catchersWrapper(throwingPromise.then(_ => cb ? cb(_) : _));
const responseChain = {
_wretchReq: wretch,
_fetchReq,
res: bodyParser(null),
json: bodyParser("json"),
blob: bodyParser("blob"),
formData: bodyParser("formData"),
arrayBuffer: bodyParser("arrayBuffer"),
text: bodyParser("text"),
error(errorId, cb) {
catchers.set(errorId, cb);
return this;
},
badRequest(cb) { return this.error(400, cb); },
unauthorized(cb) { return this.error(401, cb); },
forbidden(cb) { return this.error(403, cb); },
notFound(cb) { return this.error(404, cb); },
timeout(cb) { return this.error(408, cb); },
internalError(cb) { return this.error(500, cb); },
fetchError(cb) { return this.error(FETCH_ERROR, cb); },
};
const enhancedResponseChain = addons.reduce((chain, addon) => ({
...chain,
...addon.resolver
}), responseChain);
return resolvers.reduce((chain, r) => r(chain, wretch), enhancedResponseChain);
};
//# sourceMappingURL=resolver.js.map