restify
Version:
REST framework
153 lines (129 loc) • 4.49 kB
JavaScript
;
// core modules
var util = require('util');
// external modules
var WError = require('verror').WError;
// internal files
var helpers = require('./../helpers');
/**
* Base HttpError class. inherits from WError.
* Variadic signature, first two are special to Restify, using a options obj.
* 1) new HttpError(anotherErr, {...});
* 2) new HttpError({...});
* Last one is a straight pass through to WError
* 3) new HttpError('my special error message');
* @public
* @class
*/
function HttpError() {
var self = this;
// normalize the signatures
var parsed = helpers.parseVariadicArgs(arguments, true);
var args = parsed.args;
var options = parsed.options || {};
// inherit from WError, call super first before doing anything else! WError
// will handle calling captureStackTrace, using arguments.callee to
// eliminate unnecessary stack frames.
WError.apply(self, args);
/**
* the error message.
* since constructor can be invoked with both options.message, as well as
* printf style messages, prefer the printf style messages that are already
* set by WError constructor. Since we've already invoked WError constructor
* at this point, only use options.message value if message is not yet
* defined. in short, prefer printf messages over options.message when both
* are passed in. support default message if set on the prototype for custom
* constructors.
* @property
* @type {String}
*/
if (!self.message) {
self.message = (options.message || self.message) ||
Object.getPrototypeOf(self).message || '';
}
/**
* the http status code of the error.
* because inherited classes have status code set on the prototype,
* only assign a status code if truthy.
* @property
* @type {Number}
*/
if (options.statusCode) {
self.statusCode = options.statusCode;
}
/**
* property used to describe the error. emulates some of the core module
* errors that have codes on them to describe their nature,
* i.e., fs.readFile can return an ENOENT error where err.code is 'ENOENT'
* @property
* @type {String}
*/
if (options.code) {
self.code = options.code;
}
/**
* an object used to render the error when passed
* to res.send()
* @property
* @type {Object}
*/
self.body = {
// err.code/err.restCode is used by legacy restify paths, probably
// originally created to emulate the code property that is created by
// some native core module errors (i.e., a failed fs.readFile will
// return a ENOENT error with a err.code of ENOENT).
//
// for Http/RestErrors, the code will be the error name but with
// 'error' truncated from the string. i.e., if the error name is
// InternalServerError, the code is InternalServer.
code: options.code || self.code,
message: self.message || ''
};
/**
* an object of random properties that may be added to the object upon
* instantion. useful for capturing context around a specific error.
* @property
* @type {Object}
*/
self.context = options.context || null;
}
util.inherits(HttpError, WError);
/**
* assign non-standard display name property on the CONSTRUCTOR (not prototype),
* which is supported by all VMs. useful for stack trace output.
* @type {String}
*/
HttpError.displayName = 'HttpError';
/**
* the name of the error, used in the stack trace output
* @type {String}
*/
HttpError.prototype.name = 'HttpError';
/**
* the default error code
* @type {String}
*/
HttpError.prototype.code = 'Error';
/**
* implement a basic toString/JSON.stringify. they should be identical.
* @public
* @method toJSON
* @returns {String}
*/
HttpError.prototype.toJSON = function toJSON() {
var self = this;
var message = '';
// if we have a cause, get the full VError toString() without the current
// error name. verbose check, self.cause can exist but returns undefined
if (self.cause && typeof self.cause === 'function' && self.cause()) {
var fullString = self.toString();
message = fullString.substr(fullString.indexOf(' ') + 1);
} else {
message = self.body.message;
}
return {
code: self.body.code,
message: message
};
};
module.exports = HttpError;