UNPKG

@aspectus/resource

Version:
200 lines (169 loc) 5.46 kB
/* eslint-disable prefer-spread */ import pipe from 'ramda/src/pipe'; import prop from 'ramda/src/prop'; import { createResource } from './resource'; import { sameResult, isFunction } from './utils'; const orderCmp = (a, b) => a.order - b.order || a.index - b.index; const transformerTransducer = (acc, t) => acc.then.apply(acc, t); class ResourceChain { constructor(parameters) { this.parameters = parameters || {}; } getResource() { if (!this.preparedResource) { this.preparedResource = createResource(this.getParameters()); } return this.preparedResource; } getParameters() { if (!this.preparedParameters) { this.preparedParameters = { ...this.parameters, middleware: this.getMiddleware(), }; } return this.preparedParameters; } getMiddleware() { if (this.preparedMiddleware) { return this.preparedMiddleware; } const { middleware = [] } = this.parameters; this.preparedMiddleware = middleware.length ? pipe.apply( this, middleware.sort(orderCmp).map(prop('middleware')) ) : sameResult; return this.preparedMiddleware; } getTransformers() { if (this.preparedTransformers) { return this.preparedTransformers; } const { transformers = [] } = this.parameters; this.preparedTransformers = transformers.sort(orderCmp).map(prop('args')); return this.preparedTransformers; } /** * Overrides `urlGetter`. * * @param {Function} urlGetter - Function that returns url based on passed * parameters. * @returns Resource - New Resource instance with overrided urlGetter. * @memberof Resource */ url(urlGetter) { return new this.constructor({ ...this.parameters, urlGetter }); } /** * Overrides `fetcher`. * * @param {Function} fetcher - Function that implements Fetch API. * @returns Resource - New Resource instance with overrided fetcher. * @memberof Resource */ fetcher(fetcher) { return new this.constructor({ ...this.parameters, fetcher }); } /** * Adds new middleware to the set of existing middlewares list. * * @param {Function} middleware - Middleware that transforms parameters, * config, body, headers to fit your needs. * @param {int} order - Middleware execution order. Must be between 0 - 1000. * Default is 500. * @returns Resource - New Resource instance with added middleware. * @memberof Resource */ middleware(middleware, order = 500) { const previous = this.parameters.middleware || []; return new this.constructor({ ...this.parameters, middleware: [{ middleware, order, index: previous.length }].concat(previous), }); } /** * Adds new transformer to the set of existing transformers list. * * @param {Function} then - Transformer that transforms result body. * @param {Function} catcher - Error catcher. * @param {int} order - Transformer execution order. Must be between 0 - 1000. * Default is 500. * @returns Resource - New Resource instance with added transformer. * @memberof Resource */ transform(then, catcher, order = 500) { const args = [then]; const previous = this.parameters.transformers || []; if (isFunction(catcher)) { args.push(catcher); } return new this.constructor({ ...this.parameters, transformers: [{ args, order, index: previous.length }].concat(previous), }); } merge(config, key, value = null) { const object = value !== null ? { [key]: value } : key; return new this.constructor({ ...this.parameters, [config]: { ...this.parameters[config], ...object }, }); } /** * Object to merge into `config`(Fetch API configuration object). * * @param {*} key - Key for a singular change. Or Object with multiple * key-value pairs. * @param {*} value - Value for provided key. Or nothing if the first * argument is Object. * @returns Resource - New Resource instance with changed Fetch API config. * @memberof Resource */ config(key, value) { return this.merge('config', key, value); } /** * Object to merge into `headers` configuration. * * @param {*} key - Key for a singular change. Or Object with multiple * headers. * @param {string} value - Value for provided key. Or nothing if the first * argument is Object. * @returns Resource - New Resource instance with changed headers. * @memberof Resource */ headers(key, value) { return this.merge('headers', key, value); } /** * Make API call to the resource * * @param {*} args - Arguments, required to make an API call. * @returns Promise - Result of the api call. * @memberof Resource */ makeRequest() { const resource = this.getResource(); return resource.apply(this, arguments); // eslint-disable-line prefer-rest-params } applyTransformers(promise) { const transformers = this.getTransformers(); return transformers.reduce(transformerTransducer, promise); } /** * Execute chain * * @param {*} args - Arguments, required to make an API call. * @returns Promise - Transformed result of api call. * @memberof Resource */ execute() { return this.applyTransformers( this.makeRequest.apply(this, arguments) // eslint-disable-line prefer-rest-params ); } } export { ResourceChain, }; export default ResourceChain;