Merge pull request #787 from strongloop/feature/app-middleware-v2

Implement app.middlewareFromConfig
This commit is contained in:
Miroslav Bajtoš 2014-11-11 19:41:46 +01:00
commit beb55ee9f4
2 changed files with 112 additions and 13 deletions

View File

@ -1,3 +1,4 @@
var assert = require('assert');
var express = require('express');
var merge = require('util')._extend;
var PhaseList = require('loopback-phase').PhaseList;
@ -12,6 +13,47 @@ module.exports = function loopbackExpress() {
return app;
};
/**
* Register a middleware using a factory function and a JSON config.
*
* **Example**
*
* ```js
* app.middlewareFromConfig(compression, {
* enabled: true,
* phase: 'initial',
* config: {
* threshold: 128
* }
* });
* ```
*
* @param {function} factory The factory function creating a middleware handler.
* Typically a result of `require()` call, e.g. `require('compression')`.
* @param {Array|*} config The configuration. Either an array of arguments
* to pass to the factory function, or the value of the first argument
* when the factory expects a single argument only.
*/
proto.middlewareFromConfig = function(factory, config) {
assert(typeof factory === 'function', '"factory" must be a function');
assert(typeof config === 'object', '"config" must be an object');
assert(typeof config.phase === 'string' && config.phase,
'"config.phase" must be a non-empty string');
if (config.enabled === false)
return;
var args = config.config;
if (args === undefined) {
args = [];
} else if (!Array.isArray(args)) {
args = [args];
}
var handler = factory.apply(null, args);
this.middleware(config.phase, handler);
};
/**
* Register a middleware handler to be executed in a given phase.
* @param {string} name The phase name, e.g. "init" or "routes".
@ -23,6 +65,9 @@ module.exports = function loopbackExpress() {
proto.middleware = function(name, handler) {
this.lazyrouter();
assert(typeof name === 'string' && name, '"name" must be a non-empty string');
assert(typeof handler === 'function', '"handler" must be a function');
var fullName = name;
var handlerName = handler.name || '(anonymous)';

View File

@ -1,4 +1,5 @@
var path = require('path');
var http = require('http');
var loopback = require('../');
var PersistedModel = loopback.PersistedModel;
@ -27,7 +28,7 @@ describe('app', function() {
});
app.use(namedHandler('main'));
executeHandlers(function(err) {
executeMiddlewareHandlers(app, function(err) {
if (err) return done(err);
expect(steps).to.eql([
'initial', 'session', 'auth', 'parse',
@ -42,7 +43,7 @@ describe('app', function() {
app.middleware('routes:after', namedHandler('routes:after'));
app.use(namedHandler('main'));
executeHandlers(function(err) {
executeMiddlewareHandlers(app, function(err) {
if (err) return done(err);
expect(steps).to.eql(['routes:before', 'main', 'routes:after']);
done();
@ -64,7 +65,7 @@ describe('app', function() {
next();
});
executeHandlers(function(err) {
executeMiddlewareHandlers(app, function(err) {
if (err) return done(err);
expect(steps).to.eql(['initial', 'error']);
done();
@ -78,7 +79,7 @@ describe('app', function() {
next(expectedError);
});
executeHandlers(function(err) {
executeMiddlewareHandlers(app, function(err) {
expect(err).to.equal(expectedError);
done();
});
@ -90,18 +91,59 @@ describe('app', function() {
next();
};
}
});
function executeHandlers(callback) {
var server = http.createServer(function(req, res) {
app.handle(req, res, callback);
describe.onServer('.middlewareFromConfig', function() {
it('provides API for loading middleware from JSON config', function(done) {
var steps = [];
var expectedConfig = { key: 'value' };
var handlerFactory = function() {
var args = Array.prototype.slice.apply(arguments);
return function(req, res, next) {
steps.push(args);
next();
};
};
// Config as an object (single arg)
app.middlewareFromConfig(handlerFactory, {
enabled: true,
phase: 'session',
config: expectedConfig
});
request(server)
.get('/test/url')
.end(function(err) {
if (err) return callback(err);
});
}
// Config as a value (single arg)
app.middlewareFromConfig(handlerFactory, {
enabled: true,
phase: 'session:before',
config: 'before'
});
// Config as a list of args
app.middlewareFromConfig(handlerFactory, {
enabled: true,
phase: 'session:after',
config: ['after', 2]
});
// Disabled by configuration
app.middlewareFromConfig(handlerFactory, {
enabled: false,
phase: 'initial',
config: null
});
executeMiddlewareHandlers(app, function(err) {
if (err) return done(err);
expect(steps).to.eql([
['before'],
[expectedConfig],
['after', 2]
]);
done();
});
});
});
describe('app.model(Model)', function() {
@ -470,3 +512,15 @@ describe('app', function() {
});
});
});
function executeMiddlewareHandlers(app, callback) {
var server = http.createServer(function(req, res) {
app.handle(req, res, callback);
});
request(server)
.get('/test/url')
.end(function(err) {
if (err) return callback(err);
});
}