@northscaler/service-support
Version:
Artifacts that assist in writing service layers effectively
135 lines (123 loc) • 12.8 kB
JavaScript
;
const ResponseStatus = require('../enums/ResponseStatus');
const defaultErrorFormatter = require('../formatters/error-formatter');
const defaultDateFormatter = require('../formatters/date-formatter');
const DateFormat = require('../enums/DateFormat');
function formatValuesIn({
value,
formatters
} = {}) {
if (!value) return value;
if (Array.isArray(value)) return value.map(it => formatValuesIn({
value: it,
formatters
}));
for (const formatter of formatters) {
if (value instanceof formatter.type) return formatter.formatter(value);
}
if (typeof value === 'object') {
return Object.keys(value).reduce((accum, next) => {
value[next] = formatValuesIn({
value: value[next],
formatters
});
return accum;
}, value);
}
return value;
}
/**
* Function used to execute the given function in a `try`/`catch` block.
* If the function returns normally, the return value is wrapped in a service response object with the following shape:
* ```
* {
* data: <function return value>,
* meta: {
* status: ResponseStatus.SUCCESS,
* elapsedMillis: n
* }
* }
* ```
* If the function throws, the `Error` is caught, and formatted as a service response object with the following shape:
* ```
* {
* error: {
* name: ...,
* message: ...,
* code: ...,
* info: ...,
* cause: ...,
* stack: ...,
* },
* meta: {
* status: ResponseStatus.FAILURE,
* elapsedMillis: n
* }
* }
* ```
*
* @private
* @param {object} arg0 The argument to be deconstructed.
* @param {function} arg0.fn The function to be called.
* @param {Formatter[]} [arg0.formatters] Formatters to be used when formatting values in returned objects or thrown `Error`s.
* Shape is `{ type, formatter }`, where `type` is a type like `Date`, `Error`, etc and `formatter` is the formatting function.
* Example: `{ type: Date, formatter: date => date.toString() }`.
* Appropriate defaults are provided.
* @param {boolean} [arg0.includeErrorStacks=true] Whether to include the `Error` `stack` property if one is thrown or there are `Error`s in the return value.
* Ignored if `formatters` is given.
* @param {boolean} [arg0.includeErrorCauses=true] Whether to include the `Error` `cause` property if one is thrown or there are `Error`s in the return value.
* Ignored if `formatters` is given.
* @param {DateFormat} [arg0.dateFormat=DateFormat.ISO_8601] The date format to use.
* Ignored if `formatters` is given.
* @return {Promise<{meta: {elapsedMillis: number, status: *}, error: *}|{data: *, meta: {elapsedMillis: number, status: *}}>}
*/
async function servicifyOutcomeOf({
fn,
formatters,
includeErrorStacks = true,
includeErrorCauses = true,
dateFormat = DateFormat.ISO_8601
} = {}) {
formatters = formatters || [{
type: Error,
formatter: error => defaultErrorFormatter({
error,
includeStack: includeErrorStacks,
includeCause: includeErrorCauses
})
}, {
type: Date,
formatter: date => defaultDateFormatter({
date,
format: dateFormat
})
}];
formatters = Array.isArray(formatters) ? formatters : [formatters];
const begin = Date.now();
try {
const value = await fn();
return {
data: formatValuesIn({
value,
formatters
}),
meta: {
status: ResponseStatus.SUCCESS.name,
elapsedMillis: Date.now() - begin
}
};
} catch (e) {
return {
error: formatValuesIn({
value: e,
formatters
}),
meta: {
status: ResponseStatus.FAILURE.name,
elapsedMillis: Date.now() - begin
}
};
}
}
module.exports = servicifyOutcomeOf;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9tYWluL3NlcnZpY2Uvc2VydmljaWZ5T3V0Y29tZU9mLmpzIl0sIm5hbWVzIjpbIlJlc3BvbnNlU3RhdHVzIiwicmVxdWlyZSIsImRlZmF1bHRFcnJvckZvcm1hdHRlciIsImRlZmF1bHREYXRlRm9ybWF0dGVyIiwiRGF0ZUZvcm1hdCIsImZvcm1hdFZhbHVlc0luIiwidmFsdWUiLCJmb3JtYXR0ZXJzIiwiQXJyYXkiLCJpc0FycmF5IiwibWFwIiwiaXQiLCJmb3JtYXR0ZXIiLCJ0eXBlIiwiT2JqZWN0Iiwia2V5cyIsInJlZHVjZSIsImFjY3VtIiwibmV4dCIsInNlcnZpY2lmeU91dGNvbWVPZiIsImZuIiwiaW5jbHVkZUVycm9yU3RhY2tzIiwiaW5jbHVkZUVycm9yQ2F1c2VzIiwiZGF0ZUZvcm1hdCIsIklTT184NjAxIiwiRXJyb3IiLCJlcnJvciIsImluY2x1ZGVTdGFjayIsImluY2x1ZGVDYXVzZSIsIkRhdGUiLCJkYXRlIiwiZm9ybWF0IiwiYmVnaW4iLCJub3ciLCJkYXRhIiwibWV0YSIsInN0YXR1cyIsIlNVQ0NFU1MiLCJuYW1lIiwiZWxhcHNlZE1pbGxpcyIsImUiLCJGQUlMVVJFIiwibW9kdWxlIiwiZXhwb3J0cyJdLCJtYXBwaW5ncyI6IkFBQUE7O0FBRUEsTUFBTUEsY0FBYyxHQUFHQyxPQUFPLENBQUMseUJBQUQsQ0FBOUI7O0FBQ0EsTUFBTUMscUJBQXFCLEdBQUdELE9BQU8sQ0FBQywrQkFBRCxDQUFyQzs7QUFDQSxNQUFNRSxvQkFBb0IsR0FBR0YsT0FBTyxDQUFDLDhCQUFELENBQXBDOztBQUNBLE1BQU1HLFVBQVUsR0FBR0gsT0FBTyxDQUFDLHFCQUFELENBQTFCOztBQUVBLFNBQVNJLGNBQVQsQ0FBeUI7QUFDdkJDLEVBQUFBLEtBRHVCO0FBRXZCQyxFQUFBQTtBQUZ1QixJQUdyQixFQUhKLEVBR1E7QUFDTixNQUFJLENBQUNELEtBQUwsRUFBWSxPQUFPQSxLQUFQO0FBRVosTUFBSUUsS0FBSyxDQUFDQyxP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QVU7QUFDVixXQUFPO0FBQ0xkLE1BQUFBLEtBQUssRUFBRXJCLGNBQWMsQ0FBQztBQUFFQyxRQUFBQSxLQUFLLEVBQUVrQyxDQUFUO0FBQVlqQyxRQUFBQTtBQUFaLE9BQUQsQ0FEaEI7QUFFTDRCLE1BQUFBLElBQUksRUFBRTtBQUNKQyxRQUFBQSxNQUFNLEVBQUVwQyxjQUFjLENBQUN5QyxPQUFmLENBQXVCSCxJQUQzQjtBQUVKQyxRQUFBQSxhQUFhLEVBQUVWLElBQUksQ0FBQ0ksR0FBTCxLQUFhRDtBQUZ4QjtBQUZELEtBQVA7QUFPRDtBQUNGOztBQUVEVSxNQUFNLENBQUNDLE9BQVAsR0FBaUJ4QixrQkFBakIiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCdcblxuY29uc3QgUmVzcG9uc2VTdGF0dXMgPSByZXF1aXJlKCcuLi9lbnVtcy9SZXNwb25zZVN0YXR1cycpXG5jb25zdCBkZWZhdWx0RXJyb3JGb3JtYXR0ZXIgPSByZXF1aXJlKCcuLi9mb3JtYXR0ZXJzL2Vycm9yLWZvcm1hdHRlcicpXG5jb25zdCBkZWZhdWx0RGF0ZUZvcm1hdHRlciA9IHJlcXVpcmUoJy4uL2Zvcm1hdHRlcnMvZGF0ZS1mb3JtYXR0ZXInKVxuY29uc3QgRGF0ZUZvcm1hdCA9IHJlcXVpcmUoJy4uL2VudW1zL0RhdGVGb3JtYXQnKVxuXG5mdW5jdGlvbiBmb3JtYXRWYWx1ZXNJbiAoe1xuICB2YWx1ZSxcbiAgZm9ybWF0dGVyc1xufSA9IHt9KSB7XG4gIGlmICghdmFsdWUpIHJldHVybiB2YWx1ZVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLm1hcChpdCA9PiBmb3JtYXRWYWx1ZXNJbih7IHZhbHVlOiBpdCwgZm9ybWF0dGVycyB9KSlcblxuICBmb3IgKGNvbnN0IGZvcm1hdHRlciBvZiBmb3JtYXR0ZXJzKSB7XG4gICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgZm9ybWF0dGVyLnR5cGUpIHJldHVybiBmb3JtYXR0ZXIuZm9ybWF0dGVyKHZhbHVlKVxuICB9XG5cbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gT2JqZWN0LmtleXModmFsdWUpLnJlZHVjZSgoYWNjdW0sIG5leHQpID0+IHtcbiAgICAgIHZhbHVlW25leHRdID0gZm9ybWF0VmFsdWVzSW4oeyB2YWx1ZTogdmFsdWVbbmV4dF0sIGZvcm1hdHRlcnMgfSlcbiAgICAgIHJldHVybiBhY2N1bVxuICAgIH0sIHZhbHVlKVxuICB9XG5cbiAgcmV0dXJuIHZhbHVlXG59XG5cbi8qKlxuICogRnVuY3Rpb24gdXNlZCB0byBleGVjdXRlIHRoZSBnaXZlbiBmdW5jdGlvbiBpbiBhIGB0cnlgL2BjYXRjaGAgYmxvY2suXG4gKiBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyBub3JtYWxseSwgdGhlIHJldHVybiB2YWx1ZSBpcyB3cmFwcGVkIGluIGEgc2VydmljZSByZXNwb25zZSBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHNoYXBlOlxuICogYGBgXG4gKiB7XG4gKiAgIGRhdGE6IDxmdW5jdGlvbiByZXR1cm4gdmFsdWU+LFxuICogICBtZXRhOiB7XG4gKiAgICAgc3RhdHVzOiBSZXNwb25zZVN0YXR1cy5TVUNDRVNTLFxuICogICAgIGVsYXBzZWRNaWxsaXM6IG5cbiAqICAgfVxuICogfVxuICogYGBgXG4gKiBJZiB0aGUgZnVuY3Rpb24gdGhyb3dzLCB0aGUgYEVycm9yYCBpcyBjYXVnaHQsIGFuZCBmb3JtYXR0ZWQgYXMgYSBzZXJ2aWNlIHJlc3BvbnNlIG9iamVjdCB3aXRoIHRoZSBmb2xsb3dpbmcgc2hhcGU6XG4gKiBgYGBcbiAqIHtcbiAqICAgZXJyb3I6IHtcbiAqICAgICBuYW1lOiAuLi4sXG4gKiAgICAgbWVzc2FnZTogLi4uLFxuICogICAgIGNvZGU6IC4uLixcbiAqICAgICBpbmZvOiAuLi4sXG4gKiAgICAgY2F1c2U6IC4uLixcbiAqICAgICBzdGFjazogLi4uLFxuICogICB9LFxuICogICBtZXRhOiB7XG4gKiAgICAgc3RhdHVzOiBSZXNwb25zZVN0YXR1cy5GQUlMVVJFLFxuICogICAgIGVsYXBzZWRNaWxsaXM6IG5cbiAqICAgfVxuICogfVxuICogYGBgXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmcwIFRoZSBhcmd1bWVudCB0byBiZSBkZWNvbnN0cnVjdGVkLlxuICogQHBhcmFtIHtmdW5jdGlvbn0gYXJnMC5mbiBUaGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkLlxuICogQHBhcmFtIHtGb3JtYXR0ZXJbXX0gW2FyZzAuZm9ybWF0dGVyc10gRm9ybWF0dGVycyB0byBiZSB1c2VkIHdoZW4gZm9ybWF0dGluZyB2YWx1ZXMgaW4gcmV0dXJuZWQgb2JqZWN0cyBvciB0aHJvd24gYEVycm9yYHMuXG4gKiBTaGFwZSBpcyBgeyB0eXBlLCBmb3JtYXR0ZXIgfWAsIHdoZXJlIGB0eXBlYCBpcyBhIHR5cGUgbGlrZSBgRGF0ZWAsIGBFcnJvcmAsIGV0YyBhbmQgYGZvcm1hdHRlcmAgaXMgdGhlIGZvcm1hdHRpbmcgZnVuY3Rpb24uXG4gKiBFeGFtcGxlOiBgeyB0eXBlOiBEYXRlLCBmb3JtYXR0ZXI6IGRhdGUgPT4gZGF0ZS50b1N0cmluZygpIH1gLlxuICogQXBwcm9wcmlhdGUgZGVmYXVsdHMgYXJlIHByb3ZpZGVkLlxuICogQHBhcmFtIHtib29sZWFufSBbYXJnMC5pbmNsdWRlRXJyb3JTdGFja3M9dHJ1ZV0gV2hldGhlciB0byBpbmNsdWRlIHRoZSBgRXJyb3JgIGBzdGFja2AgcHJvcGVydHkgaWYgb25lIGlzIHRocm93biBvciB0aGVyZSBhcmUgYEVycm9yYHMgaW4gdGhlIHJldHVybiB2YWx1ZS5cbiAqIElnbm9yZWQgaWYgYGZvcm1hdHRlcnNgIGlzIGdpdmVuLlxuICogQHBhcmFtIHtib29sZWFufSBbYXJnMC5pbmNsdWRlRXJyb3JDYXVzZXM9dHJ1ZV0gV2hldGhlciB0byBpbmNsdWRlIHRoZSBgRXJyb3JgIGBjYXVzZWAgcHJvcGVydHkgaWYgb25lIGlzIHRocm93biBvciB0aGVyZSBhcmUgYEVycm9yYHMgaW4gdGhlIHJldHVybiB2YWx1ZS5cbiAqIElnbm9yZWQgaWYgYGZvcm1hdHRlcnNgIGlzIGdpdmVuLlxuICogQHBhcmFtIHtEYXRlRm9ybWF0fSBbYXJnMC5kYXRlRm9ybWF0PURhdGVGb3JtYXQuSVNPXzg2MDFdIFRoZSBkYXRlIGZvcm1hdCB0byB1c2UuXG4gKiBJZ25vcmVkIGlmIGBmb3JtYXR0ZXJzYCBpcyBnaXZlbi5cbiAqIEByZXR1cm4ge1Byb21pc2U8e21ldGE6IHtlbGFwc2VkTWlsbGlzOiBudW1iZXIsIHN0YXR1czogKn0sIGVycm9yOiAqfXx7ZGF0YTogKiwgbWV0YToge2VsYXBzZWRNaWxsaXM6IG51bWJlciwgc3RhdHVzOiAqfX0+fVxuICovXG5hc3luYyBmdW5jdGlvbiBzZXJ2aWNpZnlPdXRjb21lT2YgKHtcbiAgZm4sXG4gIGZvcm1hdHRlcnMsXG4gIGluY2x1ZGVFcnJvclN0YWNrcyA9IHRydWUsXG4gIGluY2x1ZGVFcnJvckNhdXNlcyA9IHRydWUsXG4gIGRhdGVGb3JtYXQgPSBEYXRlRm9ybWF0LklTT184NjAxXG59ID0ge30pIHtcbiAgZm9ybWF0dGVycyA9IGZvcm1hdHRlcnMgfHwgW3tcbiAgICB0eXBlOiBFcnJvcixcbiAgICBmb3JtYXR0ZXI6IGVycm9yID0+IGRlZmF1bHRFcnJvckZvcm1hdHRlcih7XG4gICAgICBlcnJvcixcbiAgICAgIGluY2x1ZGVTdGFjazogaW5jbHVkZUVycm9yU3RhY2tzLFxuICAgICAgaW5jbHVkZUNhdXNlOiBpbmNsdWRlRXJyb3JDYXVzZXNcbiAgICB9KVxuICB9LCB7XG4gICAgdHlwZTogRGF0ZSxcbiAgICBmb3JtYXR0ZXI6IGRhdGUgPT4gZGVmYXVsdERhdGVGb3JtYXR0ZXIoe1xuICAgICAgZGF0ZSxcbiAgICAgIGZvcm1hdDogZGF0ZUZvcm1hdFxuICAgIH0pXG4gIH1dXG4gIGZvcm1hdHRlcnMgPSBBcnJheS5pc0FycmF5KGZvcm1hdHRlcnMpID8gZm9ybWF0dGVycyA6IFtmb3JtYXR0ZXJzXVxuXG4gIGNvbnN0IGJlZ2luID0gRGF0ZS5ub3coKVxuXG4gIHRyeSB7XG4gICAgY29uc3QgdmFsdWUgPSBhd2FpdCBmbigpXG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGE6IGZvcm1hdFZhbHVlc0luKHsgdmFsdWUsIGZvcm1hdHRlcnMgfSksXG4gICAgICBtZXRhOiB7XG4gICAgICAgIHN0YXR1czogUmVzcG9uc2VTdGF0dXMuU1VDQ0VTUy5uYW1lLFxuICAgICAgICBlbGFwc2VkTWlsbGlzOiBEYXRlLm5vdygpIC0gYmVnaW5cbiAgICAgIH1cbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4ge1xuICAgICAgZXJyb3I6IGZvcm1hdFZhbHVlc0luKHsgdmFsdWU6IGUsIGZvcm1hdHRlcnMgfSksXG4gICAgICBtZXRhOiB7XG4gICAgICAgIHN0YXR1czogUmVzcG9uc2VTdGF0dXMuRkFJTFVSRS5uYW1lLFxuICAgICAgICBlbGFwc2VkTWlsbGlzOiBEYXRlLm5vdygpIC0gYmVnaW5cbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzZXJ2aWNpZnlPdXRjb21lT2ZcbiJdfQ==