Returns the error constructor by the given code or
name.
errors.find(404);
// => Http404Error
errors.find(500);
// => Http500Error
errors.find('Http401Error');
// => http401Error
exports.find = function(err) {
return (typeof err == 'number') ? codes[err] : names[err];
};
Create a new constructor instance based
on the given options.
This factory method allows consumers to build
parameterized error constructor function instances
which can then be used to instantiate new concrete
instances of the given error.
This method accepts jQuery style options
argument
with the following properties (note that name
is
the only required property, all others are optional).
The scope
option can be used to change the default
namespace to create the constructor in. If unspecified
it defaults to the exports
object of this module
(i.e. errors.exports
).
The parent
option specifies the parent to inherit
from. If unspecified it defaults to Error
.
The defaultMessage
, defaultExplanation
anddefaultResponse
define the default text to use
for the new errors message
, explanation
andresponse
respectively. These values can be
overridden at construction time.
The code
specifies the error code for the new
error. If unspecified it defaults to a generated
error number which is greater than or equal to
600.
// use all defaults
errors.create({name: 'FileNotFoundError'});
throw new errors.FileNotFoundError("Could not find file x");
// inheritance
errors.create({
name: 'FatalError',
code: 900
});
errors.create({
name: 'DatabaseError',
parent: errors.FatalError
code: 901
});
var dbe = new errors.DatabaseError("Internal database error");
dbe instanceof errors.FatalError;
// => true
// scoping to current module exports
var MalformedEncodingError = errors.create({
name: 'MalformedEncodingError',
scope: exports
});
throw new MalformedEncodingError("Encoding not supported");
// default message
errors.create({
name: 'SocketReadError',
code: 4000,
defaultMessage: 'Could not read from socket'
});
var sre = new errors.SocketReadError();
sre.message;
// => 'Could not read from socket'
sre.code;
// => 4000
sre instanceof Error;
// => true
// explanation and response
errors.create({
name: 'SocketReadError',
code: 4000,
defaultMessage: 'Could not read from socket',
defaultExplanation: 'Unable to obtain a reference to the socket',
defaultResponse: 'Specify a different port or socket and retry the operation'
});
var sre = new errors.SocketReadError();
sre.explanation;
// => 'Unable to obtain a reference to the socket'
sre.response;
// => 'Specify a different port or socket and retry the operation'
var create = exports.create = function(options) {
var options = options || {}
, scope = options.scope || exports
, parent = options.parent || Error
, defaultMessage = options.defaultMessage
|| 'An unexpected ' + options.name + ' occurred.'
, className = options.name
, errorCode = options.code || nextCode()
, defaultExplanation = options.defaultExplanation
, defaultResponse= options.defaultResponse
, formattedStack
, stack = {};
Create a new instance of the exception optionally
specifying a message, explanation and response
for the new instance. If any of the arguments are
null, their value will default to their respective
default value use on the create
call, or will
be null if no default was specified.
scope[className] = function(msg, expl, fix) {
msg = msg || defaultMessage;
expl = expl || defaultExplanation;
fix = fix || defaultResponse;
parent.call(this, msg);
// hack around the defineProperty for stack so
// we can delay stack formatting until access
// for performance reasons
Error.captureStackTrace(stack, scope[className]);
Return the stack tracks for the error.
Object.defineProperty(this, 'stack', {
configurable: true,
enumerable: false,
get: function() {
if (!formattedStack) {
formattedStack = stack.stack.replace('[object Object]', 'Error: ' + msg);
}
return formattedStack;
}
});
Return the explanation for this error.
Object.defineProperty(this, 'explanation', {
value: expl,
configurable: true,
enumerable: true
});
Return the operator response for this error.
Object.defineProperty(this, 'response', {
value: fix,
configurable: true,
enumerable: true
});
Return the error code.
Object.defineProperty(this, 'code', {
value: errorCode,
configurable: true,
enumerable: true
});
HTTP status code of this error.
If the instance's code
is not a valid
HTTP status code it's normalized to 500.s
Object.defineProperty(this, 'status', {
value: http.STATUS_CODES[errorCode] ? errorCode : 500,
configurable: true,
// normalize for http status code and connect compat
enumerable: true
});
Name of this error.
Object.defineProperty(this, 'name', {
value: className,
configurable: true,
enumerable: true
});
Message for this error.
Object.defineProperty(this, 'message', {
value: msg,
configurable: true,
enumerable: true
});
};
util.inherits(scope[className], parent);
Return the name of the prototype.
Object.defineProperty(scope[className].prototype, 'name', {
value: className,
enumerable: true
});
Return a formatted string for this error which
includes the error's name
, message
and code
.
The string will also include the explanation
andresponse
if they are set for this instance.
Can be redefined by consumers to change formatting.
scope[className].prototype.toString = function() {
Return the JSON representation of this error
which includes it's name
, code
, message
and status
. The JSON object returned will
also include the explanation
and response
if defined for this instance.
This method can be redefined for customized
behavior of JSON.stringify()
.
scope[className].prototype.toJSON = function() {
// TODO externalization
return useStack
? mixin(this, {stack: this.stack}, true)
: mixin(this, {}, true);
};
cache(className, errorCode, scope[className]);
return scope[className];
};
Get/set the module default behavior in terms of if
stack traces should be included in toString()
,send()
ing errors, etc.
When called with no parameters this method will return
if the errors module is set to use stacks or not.
When called with a single boolean parameter this
method will interally set if stack traces should be used.
exports.stacks = function(useStacks) {
if (useStacks == null || useStacks == undefined) {
return useStack;
}
useStack = useStacks;
};
Gets/sets the module's default page title to use for
html based responses.
If called with no arguments, returns the current title
set. Otherwise when called with a single String
argument
sets the title to use for html based responses.
The default title is 'Error'.
exports.title = function(title) {
if (title == null || title == undefined) {
return pageTitle;
}
pageTitle = title;
};
Base Error
for web app HTTP based
exceptions -- all 4xx and 5xx wrappered
errors are instances of HttpError
.
create({name: 'HttpError'});
HttpError
s for all 4xx-5xx HTTP based status codes
defined as Http[code]Error
for convenience.
// Accept: text/html
res.send(new errors.Http404Error('Resource not found'));
// => text/html
// => "Resource not found"
// Accept: application/json
res.send(new errors.Http423Error('Resource is currently locked'));
// => application/json
// {
// "name": "Http423Error",
// "code": 423,
// "status": 423,
// "message": "Resource is currently locked"
// }
// Accept: text/plain
// res.send(new errors.Http401Error('You do not have access'));
// => text/plain
// "You do not have access"
for (code in http.STATUS_CODES) {
// TODO: provide default explanation & response
if (http.STATUS_CODES.hasOwnProperty(code) && code >= 400) {
create({
name: 'Http' + code + 'Error',
code: code,
parent: exports.HttpError,
defaultMessage: http.STATUS_CODES[code]
});
}
}
Custom error handler middleware based on connect'serrorHandler()
middleware. Althought out of the box
connect or express errorHandler() works just fine,
its not as pretty as you might like due to the additional
details in custom error's toString()
.
Therefore errors
exports its own errorHandler()
middleware which supports an options
object to configure
it.
The options
JSON object accepts the following properties:
exports.errorHandler = function(options) {
var opts = mixin({connectCompat: false, title: pageTitle, includeStack: useStack}
, options, true);
if (opts.connectCompat) {
return function(err, req, res, next) {
if (isError(err)) {
// connect errorHandler() compat
err.toString = function() {
return err.message;
};
}
errHandler.title = opts.title;
// connect middleware error handler
return errHandler()(err, req, res, next);
};
} else {
return defaultFormatter(opts.title, opts.includeStack);
}
};
}
If Express is installed, patch response
to
permit send
ing Error
based objects. If
vanilla Error
objects are used with send
,
they are mapped by default to the Http500Error
.
Prior to send
ing an error based response, any
mapper setup for the Error
is invoked allowing
customization or transformation of the error.
The current implementation provides direct support
for text/html
, text/plain
and application/json
based accept types, otherwise it defaults to plain/text
.
// Accept: text/html
res.send(new errors.Http404Error('Resource not found'));
// => html
// => html structured response
// Accept: application/json
res.send(new errors.Http423Error('Resource is currently locked'));
// => application/json
// => {
// => 'name': 'Http423Error',
// => 'code': 423,
// => 'status': 423,
// => 'message': 'Resource is currently locked'
// => }
// Accept: text/plain
// res.send(new errors.Http401Error('You do not have access'));
// => text/plain
// => "You do not have access"
// Accept: text/xml
// res.send(new errors.Http500Error('Something bad happened'));
// => 500
// => text/plain
if (response) {
var _send = response.send;
response.send = function(err) {
if (arguments.length == 1 && err instanceof Error) {
err = mapError(err);
if (!isError(err)) {
// map vanilla errors into 500s
err = new exports.Http500Error(err.message ||
http.STATUS_CODES[500] + ' - ' + err.name);
}
defaultFormatter(pageTitle, useStack)(err, this.req, this.req.res, null);
return this;
}
return _send.apply(this, arguments);
};
}
Adds or retrieves an error mappers.
When called with 2 arguments, this method is used to
add error mappers for the given error names.
When called with a single argument it's used to
retrieve the registered mapper for the given
error name.
Any bound mappers will be invoked
for express.send()
integration and hence you
can define mappers used when sending error responses
with Express.
// adding mappers
errors.mapper('RangeError', function(rangeError) {
return new errors.Http412Error('Invalid range requested');
})
.addmapper('ReferenceError', function(refError) {
return new errors.Http424Error('Bad reference given');
});
errors.mapper(['RangeError', 'ReferenceError'], function(err) {
return new errors.Http500Error(err.message);
});
// retrieve error mapper
var rangeError = errors.mapper('RangeError');
var mapper = exports.mapper = function(errName, fn) {
if (arguments.length == 2) {
asArray(errName).forEach(function(name) {
mappers[name] = fn;
});
return exports;
}
return mappers[errName];
};
Maps the given error using the bound error mapper
and returns the mapped error as per the mappers
return value. If no mapper is bound to the given
errors name, the argument error is returned unchanged.
errors.mapError(new RangeError());
var mapError = exports.mapError = function(err) {
return mapper(err.name) ? mapper(err.name)(err) : err;
};
JS_ERRORS
exports.JS_ERRORS
JavaScript Error constructors indexed by name
for convenience.
Examples
new errors.JS_ERRORS.URIError('Malformed URI');