dyson
Version:
Node server for dynamic, fake JSON.
90 lines (74 loc) • 2.78 kB
JavaScript
const multiRequest = require('./multiRequest');
const _ = require('lodash');
const cache = {};
const result = (prop, args) => (_.isFunction(prop) ? prop(...args) : prop);
const generate = (req, res, next) => {
const { config } = res.locals;
const options = res.app.get('dyson_options');
const { log } = res.app.get('dyson_logger');
const path = req.url;
const cacheKey = req.method + req.url;
const exposeRequest = config.exposeRequest || (options.exposeRequest && config.exposeRequest !== false);
const templateArgs = exposeRequest ? [req] : [req.params, req.query, req.body, req.cookies, req.headers];
const containerArgs = exposeRequest ? [req] : [req.params, req.query];
if (config.cache && cache[cacheKey]) {
log('Resolving response for', req.method, path, '(cached)');
res.body = cache[cacheKey];
return next();
}
if (multiRequest.isMultiRequest(path, options)) {
Promise.all(multiRequest.doMultiRequest(req, path)).then(data => {
res.body = cache[cacheKey] = data;
log('Resolving response for:', req.method, path, '(multiRequest)');
next();
});
return;
}
const template = result(config.template, templateArgs);
const isCollection = result(config.collection, templateArgs);
const size = result(config.size, templateArgs);
const responseAwait = !isCollection
? assembleResponse(template, templateArgs)
: Promise.all(_.times(size, () => assembleResponse(template, templateArgs)));
responseAwait
.then(response =>
!config.container
? response
: assembleResponse(_.result(config, 'container'), [...containerArgs, response], config)
)
.then(data => {
res.body = cache[cacheKey] = data;
log('Resolving response for', req.method, path);
next();
});
};
const isPromiseLike = obj => _.isObject(obj) && 'then' in obj;
const assembleResponse = (template = null, params, scope) =>
Promise.resolve().then(() => {
if (!template) return null;
if (typeof template === 'string') return template;
if (isPromiseLike(template)) return template;
const obj = _.isArray(template) ? [] : {};
return Promise.all(
_.map(template, (value, key) => {
if (Object.prototype.hasOwnProperty.call(template, key)) {
obj[key] = _.isFunction(value)
? value.apply(scope || obj, params)
: _.isPlainObject(value)
? assembleResponse(value, params, obj)
: value;
if (isPromiseLike(obj[key])) {
return obj[key].then(value => {
obj[key] = value;
});
}
}
})
).then(() => obj);
});
const render = (req, res) => res.send(res.body);
module.exports = {
generate,
render,
assembleResponse
};