bridge-node-server/node_server/utils/promises.js
Martin Donnelly 57bd6c8e6a init
2018-06-24 21:15:03 +01:00

143 lines
3.8 KiB
JavaScript

/**
* Support utilities for using Promises, particularls Kris Kowal's Q:
* @see {@link https://github.com/kriskowal/q}
*
* In particular, these utilities help with sending error responses through
* a promise chain. The first time an error is received, the error handler
* should call `return returnChainedError()`. Later handlers should then check
* if there is a previous error (`hasChainedError()`), and if so just send it
* on (`return resendChainedError()`). The final error handler can then return
* the chained error.
*/
'use strict';
var Q = require('q');
var httpStatus = require('http-status-codes');
var _ = require('lodash');
var debug = require('debug')('webconsole-api:utils:promises');
const ERR_KEY = 'cmcrdErrResponse';
module.exports = {
ERR_KEY: ERR_KEY,
ErrorResponse: ErrorResponse,
sendErrorResponse: sendErrorResponse,
returnChainedError: returnChainedError,
resendChainedError: resendChainedError,
hasChainedError: hasChainedError,
getChainedError: getChainedError
};
/**
* Constructs a new ErrorResponse that is used for passing errors through a
* promise chain.
*
* @class
* @param {integer} httpcode - the http status code to respond with
* @param {integer} code - the Bridge error code
* @param {String} info - the further information string
*/
function ErrorResponse(httpcode, code, info) {
//
// Assign the values
//
this.httpcode = httpcode;
this.errorInfo = {
code: code,
info: info
};
}
/**
* Returns an error in an appropriate way for chaining through a promise
* chain.
*
* @param {Object} err - the existing error for manipulating
* @param {integer} httpcode - the http status code to respond with
* @param {integer} code - the Bridge error code
* @param {String} info - the further information string
*
* return {Promise} - rejected promise with the error info added
*/
function returnChainedError(err, httpcode, code, info) {
var response = new ErrorResponse(httpcode, code, info);
//
// If err isn't already an object, turn it into one
//
if (!_.isObject(err)) {
var original = err;
err = {
originalErr: err
};
}
err[ERR_KEY] = response;
return resendChainedError(err);
}
/**
* Sends on an error again as a rejected promise
*
* @param {Object} err - the existing error for manipulating
*
* return {Promise} - rejected promise with the error info added
*/
function resendChainedError(err) {
var deferred = Q.defer();
deferred.reject(err);
return deferred.promise;
}
/**
* Checks if there is already a chained error in this error object
*
* @param {Object} err - the err reason object
*/
function hasChainedError(err) {
return err.hasOwnProperty(ERR_KEY);
}
/**
* Gets the chained error information
*
* @param {Object} err - the error object
*
* @return {?ErrorResponse} - the error response info (if any)
*/
function getChainedError(err) {
if (!hasChainedError(err)) {
return null;
} else {
return err[ERR_KEY];
}
}
/**
* Returns an error back to the client. This is either the error that has
* been passed through the promise chain, or a default unknown error is
* returned.
*
* @param {Object} res - Express response object
* @param {Object} err - the error object
*/
function sendErrorResponse(res, err) {
var response = getChainedError(err);
if (!response) {
response = new ErrorResponse(
httpStatus.INTERNAL_SERVER_ERROR,
-1,
'Unknown error'
);
}
debug(' - send error: [%s] - {%d, %s}',
response.httpcode,
response.errorInfo.code,
response.errorInfo.info
);
res.status(response.httpcode).json(response.errorInfo);
}