middlewarify
Advanced tools
Comparing version 0.0.3 to 0.0.4
@@ -15,7 +15,9 @@ /** | ||
* | ||
* @param {Object} obj An Object. | ||
* @param {string} prop The property to apply the middleware pattern on. | ||
* @param {Function=} optFinalCb Last middleware to call. | ||
* @param {Object} obj An Object. | ||
* @param {string} prop The property to apply the middleware pattern on. | ||
* @param {Function=} optFinalCb Last middleware to call. | ||
* @param {Object=} optParams Optional parameters. | ||
* @param {boolean=} throwErrors default is true. | ||
*/ | ||
middlewarify.make = function(obj, prop, optFinalCb) { | ||
middlewarify.make = function(obj, prop, optFinalCb, optParams) { | ||
@@ -25,5 +27,15 @@ var middObj = Object.create(null); | ||
middObj.finalMidd = noopMidd; | ||
middObj.params = { | ||
throwErrors: true, | ||
}; | ||
if (__.isFunction(optFinalCb)) { | ||
middObj.finalMidd = optFinalCb; | ||
} | ||
if (__.isObject(optFinalCb)) { | ||
__.extend(middObj.params, optFinalCb); | ||
} | ||
if (__.isObject(optParams)) { | ||
__.extend(middObj.params, optParams); | ||
} | ||
@@ -57,3 +69,3 @@ obj[prop] = middlewarify._runAll.bind(null, middObj); | ||
middlewarify._fetchAndInvoke(midds, args, done); | ||
middlewarify._fetchAndInvoke(midds, args, middObj.params, done); | ||
@@ -74,2 +86,3 @@ return {done: function(fn) { | ||
* @param {Array} args An array of arbitrary arguments, can be empty. | ||
* @param {Object} params Parameters passed by the user. | ||
* @param {Function} done Callback. | ||
@@ -79,3 +92,3 @@ * @param {...*} optMiddArgs Arguments passed from the last middleware. | ||
*/ | ||
middlewarify._fetchAndInvoke = function(midds, args, done, optMiddArgs) { | ||
middlewarify._fetchAndInvoke = function(midds, args, params, done, optMiddArgs) { | ||
var lastMiddArgs = optMiddArgs || []; | ||
@@ -87,4 +100,5 @@ | ||
} | ||
var midd = midds.shift(); | ||
try { | ||
var midd = midds.shift(); | ||
midd.apply(null, args.concat(function(err){ | ||
@@ -95,7 +109,11 @@ if (err) { | ||
var middArgs = Array.prototype.slice.call(arguments, 1); | ||
middlewarify._fetchAndInvoke(midds, args, done, middArgs); | ||
middlewarify._fetchAndInvoke(midds, args, params, done, middArgs); | ||
} | ||
})); | ||
} catch(ex) { | ||
done(ex); | ||
if (params.throwErrors) { | ||
throw ex; | ||
} else { | ||
done(ex); | ||
} | ||
} | ||
@@ -102,0 +120,0 @@ }; |
{ | ||
"name": "middlewarify", | ||
"description": "Apply the middleware pattern to any function.", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"homepage": "https://github.com/thanpolas/middlewarify", | ||
@@ -6,0 +6,0 @@ "author": { |
168
README.md
@@ -15,4 +15,7 @@ # Middlewarify | ||
Apply the middleware pattern: | ||
### Quick Start Examples | ||
Creating a middleware: | ||
```js | ||
@@ -24,7 +27,8 @@ var midd = require('middlewarify'); | ||
// this will be the last callback to be invoked | ||
tasks._create = function() { | ||
console.log('tasks._create'); | ||
tasks._create = function(done) { | ||
console.log('tasks._create Final Fn to be invoked'); | ||
done(); | ||
}; | ||
// Make the 'create' prop a middleware function. | ||
// Make the'create' Middleware Container. | ||
midd.make(tasks, 'create', tasks._create); | ||
@@ -40,12 +44,13 @@ ``` | ||
// add a middleware to the 'create' operation | ||
tasks.create.use(function(done){ | ||
// add middleware to the 'create' operation | ||
tasks.create.use(function(next){ | ||
console.log('middleware 1'); | ||
done(); | ||
next(); | ||
}); | ||
// add another middleware to the 'create' operation | ||
tasks.create.use(function(done){ | ||
tasks.create.use(function(next){ | ||
console.log('middleware 2'); | ||
done(); | ||
next(); | ||
}); | ||
@@ -72,38 +77,94 @@ | ||
#### make(object, property, optFinalCallback) | ||
#### make(object, property, optFinalCallback, optOptions) | ||
The `middlewarify.make()` method will apply the middleware pattern to an Object's property. | ||
The `middlewarify.make()` method will apply the middleware pattern to an Object's property, this property will be called the *Middleware Container*. | ||
```js | ||
// create a Middleware Container | ||
var crud = {}; | ||
middlewarify.make(crud, 'create'); | ||
middlewarify.make(crud, 'read'); | ||
middlewarify.make(crud, 'update'); | ||
middlewarify.make(crud, 'delete'); | ||
``` | ||
Each time `make()` is used two new functions are added to the `crud` Object: | ||
This example has created the Middleware Container `create` in the object `crud`. `create.crud` is a function that will invoke all the middleware. | ||
* `crud.create([, ...], optCallback)` This method will invoke all added middleware in the sequence they were defined. If the final argument is a Function, it will be treated as a callback after all middleware have finished. `crud.create( function( err ){ /* check err */ } )` | ||
* `crud.create.use(middleware [, ...])` This method will add middleware Functions to the `crud.create` container. | ||
You can add a third argument, the `optFinalCallback`. As the name suggests this will be the final callback to be invoked in the chain of middleware execution. This callback gets the same arguments as any other middleware. | ||
##### make() Options | ||
`make()` accepts the following options: | ||
* `throwErrors` type: **Boolean**, default: `true` If set to false all thrown errors will be suppressed and available only through the `.done()` method. | ||
```js | ||
// don't throw errors | ||
var crud = {}; | ||
middlewarify.make(crud, 'create', {throwErrors: false}); | ||
crud.create.use(function(){ | ||
throw new Error('an error'); | ||
}); | ||
// executing the middleware will not throw an error, the exception | ||
// will be available only through the .done() callback | ||
crud.create().done(function(err) { | ||
err.message === 'an error'; // true | ||
}); | ||
``` | ||
#### The use(fn) Method | ||
The middleware container exposes a `use` method to add middleware. `use()` accepts any number of parameters as long they are type Function or Arrays of Functions. | ||
The Middleware Container exposes a `use` method so you can add any number of middleware. `use()` accepts any number of parameters as long they are of type Function or Arrays of Functions. | ||
```js | ||
// create the Middleware Container | ||
var crud = {}; | ||
middlewarify.make(crud, 'create'); | ||
middlewarify.make(crud, 'create', fnFinal); | ||
// add middleware | ||
// add 3 middleware functions | ||
crud.create.use([fn1, fn2], fn3); | ||
// then add another one | ||
crud.create.use(fn4); | ||
``` | ||
#### Invoking the callbacks | ||
In the above example we added 4 middleware before the final method `fnFinal` will be invoked. A FIFO queue is implemented so the order of execution will be: | ||
The middleware container is a function that accepts any number of arguments and an optional callback. | ||
1. `fn1()` | ||
2. `fn2()` | ||
3. `fn3()` | ||
4. `fn4()` | ||
5. `fnFinal()` | ||
Any argument passed to the middleware container will also be passed to all middleware. | ||
#### Middleware Arguments | ||
All middleware gets invoked with a callback so it can pass control to the next middleware. | ||
following up on the previous examples: | ||
```js | ||
crud.create.use(function(next) { | ||
// do stuff | ||
next(); | ||
}); | ||
``` | ||
The first argument of the `next()` callback is the **error indicator**, any truthy value passed will be considered an error and stop executing the middleware chain right there and then. | ||
```js | ||
crud.create.use(function(next) { | ||
// something went wrong, bail out | ||
next('an error occured'); | ||
}); | ||
``` | ||
> If the Middleware Container is invoked with arguments, these arguments will be passed to all middleware and the callback function `next` **will always be the last argument**. Read the next section "Invoking the Middleware" for more. | ||
#### Invoking the Middleware | ||
The Middleware Container is nothing but a function that accepts any number of arguments. | ||
Any argument passed to the Middleware Container will also be passed to all middleware. | ||
```js | ||
var crud = {}; | ||
@@ -113,19 +174,47 @@ middlewarify.make(crud, 'create'); | ||
// run all middleware | ||
crud.create(userDataObject); | ||
crud.create({a: 1, b:2}, 'bar'); | ||
``` | ||
The optional callback should always be defined last, it gets invoked when all middleware have finished. It provides at least one argument, `err` which if has a truthy value (typically an instance of `Error`) meas that something did not go well. | ||
Arguments middleware will get: | ||
**The last middleware** to be invoked can pass arguments to the *Create Callback* like so: | ||
```js | ||
crud.create.use(function(arg1, arg2, next) { | ||
arg1 === {a:1, b:2}; // true | ||
arg2 === 'bar'; // true | ||
next(); | ||
}); | ||
``` | ||
#### Getting the Middleware Results and Error Handling | ||
Because any argument passed to the Middleware Container (`crud.create(arg1, arg2, fn1);`) will get piped to the middleware, we cannot add a callback within these arguments. Thus the function `.done()` is provided, so you can check for errors or results. | ||
```js | ||
crud.create(arg1, arg2, fn1).done(function(err) { | ||
if (err) { | ||
return console.error(err); | ||
} | ||
// all cool... | ||
}); | ||
``` | ||
The only way to pass arguments back to the callback of the `.done()` method is through the *Final Callback* that is defined in the `make()` method. | ||
```js | ||
var crud = {}; | ||
var lastMiddlware = function(next) { | ||
/* ... */ | ||
next(null, 'one', 'two'); | ||
var lastMiddlware = function(done) { | ||
// since this is the final middleware, we name the | ||
// callback "done" instead of "next" | ||
// and we invoke it with a null value as the first | ||
// argument to indicate there were no errors. | ||
done(null, 'one', 'two'); | ||
}); | ||
// now create the Middleware Container | ||
middlewarify.make(crud, 'create', lastMiddlware); | ||
// run all middleware | ||
crud.create(userDataObject).done(function(err, arg1, arg2) { | ||
// Invoke the Middleware Container | ||
crud.create().done(function(err, arg1, arg2) { | ||
if (err) { /* tough love */ } | ||
@@ -138,18 +227,7 @@ | ||
#### The Middleware Callback | ||
> **Beware of Error Handling** Middlewarify will catch all thrown errors from your middleware. They will be piped to the `.done()` method. So if any of your middleware functions throws an error, it will not be visible unless you setup the `.done()` callback. | ||
When adding a `middleware` Function (i.e. `crud.create.use(middleware)`) by default it will be invoked with only one argument, the `next` callback. If you add arguments when calling the middleware container `crud.create(arg1, arg2)`, all middleware callbacks will be invoked with these arguments first. The `next` callback will always be last. | ||
> Invoking next() with a truthy argument (i.e. `next(err)`) will stop invoking more middleware. The flow is passed to the `optFinalCallback` if defined in the `make()` method or silently dismissed. | ||
```js | ||
crud.create.use(function(arg1, arg2, next) { | ||
if (arg1 !== arg2) { return next(new Error('not a match'))} | ||
next(); | ||
}); | ||
crud.create(foo, bar); | ||
``` | ||
## Release History | ||
- **v0.0.4**, *10 Oct 2013* | ||
- Added option to not throw errors | ||
- **v0.0.3**, *02 Aug 2013* | ||
@@ -156,0 +234,0 @@ - Added a more explicit way to declare callbacks when invoking the middleware. |
20
test.js
@@ -130,3 +130,3 @@ /** | ||
suite('5. Failing cases', function(){ | ||
suite('5. Failing middleware cases', function(){ | ||
var obj; | ||
@@ -136,9 +136,18 @@ setup(function(){ | ||
midd.make(obj, 'create'); | ||
}); | ||
test('5.1 a middleware throws an error', function(){ | ||
test('5.1.1 middleware throws an error', function(){ | ||
obj.create.use(function(){ | ||
throw new Error('an error'); | ||
}); | ||
obj.create().done(function(err){ | ||
assert.throws(obj.create, Error); | ||
}); | ||
test('5.1.2 middleware throws an error when param is not throw', function(){ | ||
var custObj = Object.create(null); | ||
midd.make(custObj, 'create', {throwErrors: false}); | ||
custObj.create.use(function(){ | ||
throw new Error('an error'); | ||
}); | ||
custObj.create().done(function(err){ | ||
assert.instanceOf(err, Error, '"err" should be instanceOf Error'); | ||
@@ -171,4 +180,3 @@ assert.equal(err.message, 'an error', 'Error message should match'); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20968
312
243