Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# errs [](http://travis-ci.org/flatiron/errs)
Simple error creation and passing utilities focused on:
* [Creating Errors](#creating-errors)
* [Reusing Error Types](#reusing-types)
* [Merging with Existing Errors](#merging-errors)
* [Optional Callback Invocation](#optional-invocation)
* [Piping Error Events](#piping-errors)
<a name="creating-errors" />
## Creating Errors
You should know by now that [a String is not an Error][0]. Unfortunately the `Error` constructor in Javascript isn't all that convenient either. How often do you find yourself in this situation?
``` js
var err = new Error('This is an error. There are many like it.');
err.someProperty = 'more syntax';
err.someOtherProperty = 'it wont stop.';
err.notEven = 'for the mayor';
throw err;
```
Rest your fingers, `errs` is here to help. The following is equivalent to the above:
``` js
var errs = require('errs');
throw errs.create({
message: 'This is an error. There are many like it.',
someProperty: 'more syntax',
someOtherProperty: 'it wont stop.',
notEven: 'for the mayor'
});
```
<a name="reusing-types" />
## Reusing Custom Error Types
`errs` also exposes an [inversion of control][1] interface for easily reusing custom error types across your application. Custom Error Types registered with `errs` will transparently invoke `Error` constructor and `Error.captureStackTrace` to attach transparent stack traces:
``` js
/*
* file-a.js: Create and register your error type.
*
*/
var util = require('util'),
errs = require('errs');
function MyError() {
this.message = 'This is my error; I made it myself. It has a transparent stack trace.';
}
//
// Alternatively `MyError.prototype.__proto__ = Error;`
//
util.inherits(MyError, Error);
//
// Register the error type
//
errs.register('myerror', MyError);
/*
* file-b.js: Use your error type.
*
*/
var errs = require('errs');
console.log(
errs.create('myerror')
.stack
.split('\n')
);
```
The output from the two files above is shown below. Notice how it contains no references to `errs.js`:
```
[ 'MyError: This is my error; I made it myself. It has a transparent stack trace.',
' at Object.<anonymous> (/file-b.js:19:8)',
' at Module._compile (module.js:441:26)',
' at Object..js (module.js:459:10)',
' at Module.load (module.js:348:31)',
' at Function._load (module.js:308:12)',
' at Array.0 (module.js:479:10)',
' at EventEmitter._tickCallback (node.js:192:40)' ]
```
<a name="merging-errors" />
## Merging with Existing Errors
When working with errors you catch or are returned in a callback you can extend those errors with properties by using the `errs.merge` method. This will also create a human readable error message and stack-trace:
``` js
process.on('uncaughtException', function(err) {
console.log(errs.merge(err, {namespace: 'uncaughtException'}));
});
var file = fs.createReadStream('FileDoesNotExist.here');
```
``` js
{ [Error: Unspecified error]
name: 'Error',
namespace: 'uncaughtException',
errno: 34,
code: 'ENOENT',
path: 'FileDoesNotExist.here',
description: 'ENOENT, no such file or directory \'FileDoesNotExist.here\'',
stacktrace: [ 'Error: ENOENT, no such file or directory \'FileDoesNotExist.here\'' ] }
```
<a name="optional-invocation" />
## Optional Callback Invocation
Node.js handles asynchronous IO through the elegant `EventEmitter` API. In many scenarios the `callback` may be optional because you are returning an `EventEmitter` for piping or other event multiplexing. This complicates code with a lot of boilerplate:
``` js
function importantFeature(callback) {
return someAsyncFn(function (err) {
if (err) {
if (callback) {
return callback(err);
}
throw err;
}
});
}
```
`errs` it presents a common API for both emitting `error` events and invoking continuations (i.e. callbacks) with errors. If a `callback` is supplied to `errs.handle()` it will be invoked with the error. It no `callback` is provided then an `EventEmitter` is returned which emits an `error` event on the next tick:
``` js
function importantFeature(callback) {
return someAsyncFn(function (err) {
if (err) {
return errs.handle(err, callback);
}
});
}
```
<a name="piping-errors" />
## Piping Errors
Often when working with streams (especially when buffering for whatever reason), you may have already returned an `EventEmitter` or `Stream` instance by the time an error is handled.
``` js
function pipeSomething(callback) {
//
// You have a stream (e.g. http.ResponseStream) and you
// have an optional `callback`.
//
var stream = new require('stream').Stream;
//
// You need to do something async which may respond with an
// error
//
getAnotherStream(function (err, source) {
if (err) {
if (callback)
callback(err);
}
stream.emit('error', err);
return;
}
source.pipe(stream);
})
return stream;
}
```
You may pass either a `function` or `EventEmitter` instance to `errs.handle`.
``` js
function pipeSomething(callback) {
//
// You have a stream (e.g. http.ResponseStream) and you
// have an optional `callback`.
//
var stream = new require('stream').Stream;
//
// You need to do something async which may respond with an
// error
//
getAnotherStream(function (err, source) {
if (err) {
//
// Invoke the callback if it exists otherwise the stream.
//
return errs.handle(err, callback || stream);
}
source.pipe(stream);
})
return stream;
}
```
If you wish to invoke both a `callback` function and an `error` event simply pass both:
``` js
errs.handle(err, callback, stream);
```
## Methods
The `errs` modules exposes some simple utility methods:
* `.create(type, opts)`: Creates a new error instance for with the specified `type` and `opts`. If the `type` is not registered then a new `Error` instance will be created.
* `.register(type, proto)`: Registers the specified `proto` to `type` for future calls to `errors.create(type, opts)`.
* `.unregister(type)`: Unregisters the specified `type` for future calls to `errors.create(type, opts)`.
* `.handle(err, callback)`: Attempts to instantiate the given `error`. If the `error` is already a properly formed `error` object (with a `stack` property) it will not be modified.
* `.merge(err, type, opts)`: Merges an existing error with a new error instance for with the specified `type` and `opts`.
## Installation
### Installing npm (node package manager)
``` bash
$ curl http://npmjs.org/install.sh | sh
```
### Installing errs
``` bash
$ [sudo] npm install errs
```
## Tests
All tests are written with [vows][2] and should be run with [npm][3]:
``` bash
$ npm test
```
#### Author: [Charlie Robbins](http://github.com/indexzero)
#### Contributors: [Nuno Job](http://github.com/dscape)
#### License: MIT
[0]: http://www.devthought.com/2011/12/22/a-string-is-not-an-error/
[1]: http://martinfowler.com/articles/injection.html
[2]: https://vowsjs.org
[3]: https://npmjs.org