Skip to content

Commit

Permalink
Add middleware promise support
Browse files Browse the repository at this point in the history
  • Loading branch information
calebmer committed Sep 23, 2015
1 parent 2f8ac67 commit 704b06b
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 22 deletions.
51 changes: 35 additions & 16 deletions lib/router/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,37 @@ function Layer(path, options, fn) {
}
}

/**
* Ubiquitous function that handles any type
*
* Takes any number of parameters, but the last must always be a `next` function.
*
* @api private
*/

Layer.prototype.handle_any = function (/* ...args, next */) {
var self = this;
var args = Array.prototype.slice.call(arguments);
var next = args.pop();
var hasNextBeenCalled = function () { return next._layer === self; };

var handle = this.handle;
var result;

try {
result = handle.apply(undefined, args.concat([next]));
} catch (err) {
return next(err);
}

// If the result is a promise
if (result != null && typeof result.then === 'function') {
var onFulfilled = function () { if (!hasNextBeenCalled()) { next(); } };
var onRejected = function (error) { if (!hasNextBeenCalled()) { next(error); } };
result.then(onFulfilled, onRejected);
}
};

/**
* Handle the error for the layer.
*
Expand All @@ -60,18 +91,12 @@ function Layer(path, options, fn) {
*/

Layer.prototype.handle_error = function handle_error(error, req, res, next) {
var fn = this.handle;

if (fn.length !== 4) {
if (this.handle.length !== 4) {
// not a standard error handler
return next(error);
}

try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
this.handle_any(error, req, res, next);
};

/**
Expand All @@ -84,18 +109,12 @@ Layer.prototype.handle_error = function handle_error(error, req, res, next) {
*/

Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;

if (fn.length > 3) {
if (this.handle.length > 3) {
// not a standard request handler
return next();
}

try {
fn(req, res, next);
} catch (err) {
next(err);
}
this.handle_any(req, res, next);
};

/**
Expand Down
3 changes: 3 additions & 0 deletions lib/router/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ Route.prototype.dispatch = function dispatch(req, res, done) {
return done(err);
}

// Set a reference to the current layer
next._layer = layer;

if (layer.method && layer.method !== method) {
return next(err);
}
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,22 @@
},
"devDependencies": {
"after": "0.8.1",
"ejs": "2.3.3",
"istanbul": "0.3.17",
"marked": "0.3.5",
"mocha": "2.2.5",
"should": "7.0.2",
"supertest": "1.0.1",
"bluebird": "^2.10.1",
"body-parser": "~1.13.3",
"connect-redis": "~2.4.1",
"cookie-parser": "~1.3.5",
"cookie-session": "~1.2.0",
"ejs": "2.3.3",
"express-session": "~1.11.3",
"istanbul": "0.3.17",
"jade": "~1.11.0",
"marked": "0.3.5",
"method-override": "~2.3.5",
"mocha": "2.2.5",
"morgan": "~1.6.1",
"multiparty": "~4.1.2",
"should": "7.0.2",
"supertest": "1.0.1",
"vhost": "~3.0.1"
},
"engines": {
Expand Down
108 changes: 108 additions & 0 deletions test/middleware.promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@

var express = require('../');
var request = require('supertest');
var Promise = require('bluebird');

describe('middleware', function () {
describe('promises', function () {
it('resolving will be waited on', function (done) {
var app = express();
var count = 0;

app.use(function (req, res) {
count++;
return new Promise(function (resolve, reject) {
count++;
setTimeout(function () {
count++;
resolve();
}, 5);
});
});

app.use(function (req, res) {
count.should.be.exactly(3);
res.end('Awesome!')
});

request(app)
.get('/')
.expect(200, done);
});

it('rejecting will trigger error handlers', function (done) {
var app = express();

app.use(function (req, res) {
return new Promise(function (resolve, reject) {
reject(new Error('Happy error'));
});
});

request(app)
.get('/')
.expect(500, done);
});

it('will be ignored if next is called', function (done) {
var app = express();
var count = 0;

app.use(function (req, res, next) {
count++;
return new Promise(function (resolve, reject) {
count++;
next();
setTimeout(function () {
count++;
resolve();
}, 5);
});
});

app.use(function (req, res) {
count.should.be.exactly(2);
res.end('Awesome!');
});

request(app)
.get('/')
.expect(200, done);
});

it('can be used in error handlers', function (done) {
var app = express();
var count = 0;

app.use(function (req, res, next) {
count++;
next(new Error('Happy error'));
});

app.use(function (error, req, res, next) {
count++;
return new Promise(function (resolve, reject) {
count++
setTimeout(function () {
count++;
next(error);
resolve();
}, 5);
});
});

app.use(function () {
done(new Error('This should never be reached'));
});

app.use(function (error, req, res, next) {
count.should.be.exactly(4);
res.end('Awesome!');
});

request(app)
.get('/')
.expect(200, done);
});
});
});

0 comments on commit 704b06b

Please sign in to comment.