UNPKG

ketting

Version:

Opiniated HATEAOS / Rest client.

210 lines 6.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FollowPromiseMany = exports.FollowPromiseOne = void 0; const link_1 = require("./link"); const uri_1 = require("./util/uri"); const uri_template_1 = require("./util/uri-template"); /** * Base interface for both FollowOne and FollowAll */ class FollowPromise { constructor() { this.prefetchEnabled = false; this.preferPushEnabled = false; this.preferTranscludeEnabled = false; this.useHeadEnabled = false; } preFetch() { this.prefetchEnabled = true; return this; } preferPush() { this.preferPushEnabled = true; return this; } preferTransclude() { this.preferTranscludeEnabled = true; return this; } /** * Use a HTTP HEAD request to fetch the links. * * This is useful when interacting with servers that embed links in Link * Headers. */ useHead() { this.useHeadEnabled = true; return this; } } /** * The FollowPromise class is what's being returned from follow() functions. * * It's 'PromiseLike', which means you can treat it like a Promise, and it * can be awaited. When used as a Promise, it resolves to the Resource object * that was followed. * * In addition to being a Promise<Resource> stand-in, it also exposes other * functions, namely: * * * `follow()` to allow a user to chain several follow() functions to do * several 'hops' all at once. * * `followAll()`, allowing a user to call `followAll()` at the end of a * chain. */ class FollowPromiseOne extends FollowPromise { constructor(resource, rel, variables) { super(); this.resource = resource; this.rel = rel; this.variables = variables; } /** * This 'then' function behaves like a Promise then() function. * * This method signature is pretty crazy, but trust that it's pretty much * like any then() method on a promise. */ then(onfulfilled, onrejected) { return this.fetchLinkedResource().then(onfulfilled, onrejected); } /** * This 'catch' function behaves like a Promise catch() function. */ catch(onrejected) { return this.fetchLinkedResource().then(undefined, onrejected); } /** * Implementation of a Promise.finally function */ finally(onfinally) { return this.then(() => onfinally(), () => onfinally()); } /** * Follow another link immediately after following this link. * * This allows you to follow several hops of links in one go. * * For example: resource.follow('foo').follow('bar'); */ follow(rel, variables) { return new FollowPromiseOne(this.fetchLinkedResource(), rel, variables); } /** * Follows a set of links immediately after following this link. * * For example: resource.follow('foo').followAll('item'); */ followAll(rel) { return new FollowPromiseMany(this.fetchLinkedResource(), rel); } /** * This function does the actual fetching of the linked * resource. */ async fetchLinkedResource() { const resource = await this.resource; const headers = {}; if (this.preferPushEnabled) { headers['Prefer-Push'] = this.rel; } if (!this.useHeadEnabled && this.preferTranscludeEnabled) { headers.Prefer = 'transclude=' + this.rel; } let state; if (this.useHeadEnabled) { state = await resource.head({ headers }); } else { state = await resource.get({ headers }); } const link = state.links.get(this.rel); if (!link) throw new link_1.LinkNotFound(`Link with rel ${this.rel} on ${state.uri} not found`); let href; if (link.templated) { href = uri_template_1.expand(link, this.variables || {}); } else { href = uri_1.resolve(link); } const newResource = resource.go(href); if (this.prefetchEnabled) { newResource.get().catch(err => { // eslint-disable-next-line no-console console.warn('Error while prefetching linked resource', err); }); } return newResource; } } exports.FollowPromiseOne = FollowPromiseOne; /** */ class FollowPromiseMany extends FollowPromise { constructor(resource, rel) { super(); this.resource = resource; this.rel = rel; } /** * This 'then' function behaves like a Promise then() function. */ then(onfulfilled, onrejected) { return this.fetchLinkedResources().then(onfulfilled, onrejected); } /** * This 'catch' function behaves like a Promise catch() function. */ catch(onrejected) { return this.fetchLinkedResources().then(undefined, onrejected); } /** * Implementation of a Promise.finally function */ finally(onfinally) { return this.then(() => onfinally(), () => onfinally()); } /** * This function does the actual fetching, to obtained the url * of the linked resource. It returns the Resource object. */ async fetchLinkedResources() { const resource = await this.resource; const headers = {}; if (this.preferPushEnabled) { headers['Prefer-Push'] = this.rel; } if (!this.useHeadEnabled && this.preferTranscludeEnabled) { headers.Prefer = 'transclude=' + this.rel; } let state; if (this.useHeadEnabled) { state = await resource.head({ headers }); } else { state = await resource.get({ headers }); } const links = state.links.getMany(this.rel); let href; const result = []; for (const link of links) { href = uri_1.resolve(link); const newResource = resource.go(href); result.push(newResource); if (this.prefetchEnabled) { newResource.get().catch(err => { // eslint-disable-next-line no-console console.warn('Error while prefetching linked resource', err); }); } } return result; } } exports.FollowPromiseMany = FollowPromiseMany; //# sourceMappingURL=follow-promise.js.map