/**
* @summary resource-enumerate
* @version 3.0.0
* @since 1.0.0
* @author Arian Khosravi <arian.khosravi@aofl.com>
*/
import {environmentTypeEnumerate} from '@aofl/server-environment';
import {Middleware} from '@aofl/middleware';
import {ApiRequest} from '@aofl/api-request';
/**
* Resource enumerate is a special case API call that returns the interface of
* the API code in a single endpoint. The response can contain server time,
* paths to resources, and other information based on application needs. An
* advantage of this technique is that it eliminates the need to hardcode paths\urls.
*
* @memberof module:@aofl/resource-enumerate
*/
class ResourceEnumerate {
/**
* Creates an instance of ResourceEnumerate.
*
* @param {String} environment
*/
constructor(environment) {
this.environment = environment;
this.ready = new Promise((resolve) => { this.resolve = resolve; });
this.middlewareInstance = new Middleware('before', 'after');
this.apiRequestInstance = new ApiRequest();
}
/**
*
*
* @readonly
* @type {String}
*/
static get NAMESPACE() {
return 'resource-enumerate';
}
/**
* init() updates apis.url based on supplied config object.
*
* @param {Object} {apis, developmentConfig, stageConfig}
* @param {Boolean} [skipEnvironmentCheck=true] skip dev/stage config process
* @return {Promise}
*/
async init({apis, developmentConfig, stageConfig}, skipEnvironmentCheck = false) {
this.apis = apis;
for (const apiNs in this.apis) {
/* istanbul ignore next */
if (!Object.hasOwnProperty.call(this.apis, apiNs)) continue;
const api = this.apis[apiNs];
this.apiRequestInstance.addFormatter(apiNs, {
pack() {
return api.requestOptions || {};
},
unpack(response) {
return response.json();
}
});
}
if (skipEnvironmentCheck === false && this.environment !== environmentTypeEnumerate.PROD) {
await this.updateApis(developmentConfig, stageConfig);
this.resolve();
return this.ready;
}
this.resolve();
return this.ready;
}
/* istanbul ignore next */
/**
* before hook. Allows to execute some logic right before the network call is made.
*
* @param {function} fn
*/
before(fn) {
this.middlewareInstance.use(fn, 'before');
}
/* istanbul ignore next */
/**
* after hook. Allows to execute some logic immediately after the network call is made.
*
* @param {Function} fn
*/
after(fn) {
this.middlewareInstance.use(fn, 'after');
}
/**
* get() returns a promise that once resolved contains the payload from the resource enumerate
* call.
*
* @param {String} apiNs
* @param {Boolean} _fromCache
* @return {Promise}
*/
async get(apiNs, _fromCache = true) {
await this.ready;
const api = this.apis[apiNs];
let fromCache = _fromCache;
if (typeof api === 'undefined') {
throw new TypeError(`${apiNs} is not a valid api namespace.`);
}
if (!fromCache || (typeof api.invalidateCache === 'function' && api.invalidateCache.call(null))) {
this.apiRequestInstance.clearCache(ResourceEnumerate.NAMESPACE);
fromCache = false;
}
const cacheManager = this.apiRequestInstance.getCacheManager(ResourceEnumerate.NAMESPACE);
const re = cacheManager.getItem(api.url + JSON.stringify(''));
const request = {
namespace: apiNs,
cached: re !== null
};
await this.middlewareInstance.iterateMiddleware(request, 'before');
let reResp = null;
if (re !== null) {
reResp = re;
} else {
reResp = this.apiRequestInstance
.request(api.url, '', apiNs, fromCache, ResourceEnumerate.NAMESPACE);
}
return reResp.then((response) => this.middlewareInstance.iterateMiddleware(request, 'after', response));
}
/**
* updateApis() updates the api url of each namespace based on the config functions.
*
* @private
* @param {*} developmentConfig
* @param {*} stageConfig
* @return {Promise}
*/
updateApis(developmentConfig, stageConfig) {
let configFn = developmentConfig;
if (this.environment === environmentTypeEnumerate.STAGE) {
configFn = stageConfig;
}
return configFn()
.then((configModule) => {
for (const apiNs in this.apis) {
/* istanbul ignore next */
if (!Object.hasOwnProperty.call(this.apis, apiNs)) continue;
const api = this.apis[apiNs];
let variables = {};
if (typeof api[this.environment + 'Variables'] === 'function') {
variables = api[this.environment + 'Variables'].call(null);
}
api.url = configModule.default(apiNs, variables);
}
});
}
}
export {
ResourceEnumerate
};