UNPKG

@northscaler/service-support

Version:

Artifacts that assist in writing service layers effectively

135 lines (123 loc) 12.8 kB
'use strict'; 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==