error-extender
npm install @namecheap/error-extender!npm

Simplifies creation of custom Error classes for Node.js and Browser!
...which then produces stack with appended stacks of supplied cause _(very much like in Java)_!
``javascript
const extendError = require('@namecheap/error-extender');
const CustomError = extendError('CustomError');
const rootCause = new Error('the root cause');
console.log(new CustomError({ message: 'An error has occurred.', cause: rootCause }));
`
Shall output:
``
CustomError: An error has occurred.
at Object.
at Module._compile (internal/modules/cjs/loader.js:702:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
at Module.load (internal/modules/cjs/loader.js:612:32)
at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
at Function.Module._load (internal/modules/cjs/loader.js:543:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)
at startup (internal/bootstrap/node.js:240:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:564:3)
Caused by: Error: the root cause
at Object.
at Module._compile (internal/modules/cjs/loader.js:702:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:713:10)
at Module.load (internal/modules/cjs/loader.js:612:32)
at tryModuleLoad (internal/modules/cjs/loader.js:551:12)
at Function.Module._load (internal/modules/cjs/loader.js:543:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:744:10)
at startup (internal/bootstrap/node.js:240:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:564:3)
)!Features
$3
It's quite simple! See below:
`javascript
const extendError = require('@namecheap/error-extender');const AppError = extendError('AppError'); // extends
Error (default)
`Or... A bit more complex using the second argument _(options)_:
`javascript
const extendError = require('@namecheap/error-extender');const AppError = extendError('AppError', {
defaultMessage: 'An unhandled error has occurred.',
defaultData: { status: 503, message: 'An unhandled error has occurred.' }
});
const ServiceError = extendError('ServiceError', {
parent: AppError, // extends
AppError
defaultMessage: 'A service error has occurred.',
defaultData: { status: 500, message: 'A service error has occurred.' }
});const DatabaseError = extendError('DatabaseError', {
parent: ServiceError, // extends
ServiceError
defaultMessage: 'A service database error has occurred.',
defaultData: { message: 'A service database error has occurred.' }
});require('assert').deepStrictEqual(
DatabaseError.defaultData, {
status: 500,
message: 'A service database error has occurred.'
});
// no error
`Yes,
defaultData merges!####
error-extender Argumentserror-extender accepts a single object literal as second argument.The options (object literal keys) are as follows:
| key | expected type |
| ---------------- | ------------------------------------------ |
|
parent | Error.prototype _or one that extends it_ |
| defaultMessage | string |
| defaultData | any |$3
1) Creates prototype-based
Error classes (child/subclass) : _"Extended Errors"_.
1) Those _"Extended Errors"_, accepts cause (Error); very much like how it is with Java Exception.
1) Appends stack of cause to the bottom (or top) of instantiated _"Extended Errors"_ stack.
1) _"Extended Errors"_ constructor & argument _(w/ optional new)_:
1) new ExtendedError(options)
1) ExtendedError(options)Yes, much like JavaScript's native
Error, "Extended Errors" can be written/used "factory-like" (without the new keyword).#### "Extended Errors" Arguments (constructor)
"Extended Errors" accepts a single object literal as argument:
`javascript
const extendError = require('@namecheap/error-extender');
const ServiceError = extendError('ServiceError');
try {
// ... something throws something
} catch (error) {
throw new ServiceError({
message: 'An error has occurred',
data: { ref: '7e9f876ca116' },
cause: error
});
}
`The options (object literal keys) are as follows:
| key | alias | expected type |
| :-------- | :---: | ------------------- |
|
message | m | string |
| data | d | any |
| cause | c | instancedof Error |Given the alias, you may construct extended errors by:
`javascript
const extendError = require('@namecheap/error-extender');
const ServiceError = extendError('ServiceError');
try {
// ... something throws something
} catch (error) {
throw new ServiceError({
m: 'An error has occurred',
d: { ref: '7e9f876ca116' },
c: error
});
}
`Note: Aliases are evaluated first; hence if you have both
m and message, if m's value is truthy, then m's value will be used.#### Instance Properties
As with
Error, "Extended Errors" would have the following properties:*
name
* message
* stack... "Extended Errors" shall have the following additiona properties:
*
data - _(as set in constructor args)_
* cause - _(as set in constructor args)_####
data merging w/ defaultDataYes, you heard right, instance
data merges with defaultData!!!See example below:
`javascript
const extendError = require('@namecheap/error-extender');const AppError = extendError('ServiceError', {
defaultData: { status: 503, message: 'An unhandled error has occurred.' }
});
const appError = new AppError({ d: { status: 401 } });
require('assert').deepStrictEqual(
appError.data, {
status: 401,
message: 'An unhandled error has occurred.'
});
// no error
`The inspiration (thanks
bluebird!):`javascript
const Promise = require('bluebird');
// ...
const extendError = require('@namecheap/error-extender');
// ...
const ServiceError = extendError('ServiceError');
const ServiceStateError = extendError(
'ServiceStateError',
{ parent: ServiceError });
// ...
function aServiceFunction() {
return new Promise(
function (resolve, reject) {
// ... multiple things that may throw your
// custom "expected" errors
})
.catch(ServiceStateError, function (error) {
// ... your "common way" of handling
// ServiceStateError
// ... then propagate
})
.catch(ServiceError, function (error) {
// ... your "common generc way" of handling
// ServiceError
// ... then propagate
})
.catch(function (error) {
// ... the "catch all"
// ... then propagate
});
}
`With JavaScript, I felt quite stifled when I was limited to:
1) Do selective/custom handling based on matching messages from
throw new Error('..').
1) Return/propagate JSend-like responses to function "callers"/"users".
1) ... or whatever error possible passing/handling could be done, throughout functions and callers/users.With
error-extender with help from syntactic-sugar from bluebird`, you can improve _(or even standardize)_ your way of propagating/handling errors throughout your application.