Merge pull request #133 from strongloop/feature/app-install-middleware

Implement app.installMiddleware
This commit is contained in:
Miroslav Bajtoš 2014-01-13 21:58:11 -08:00
commit 57813cef56
2 changed files with 221 additions and 0 deletions

View File

@ -439,6 +439,131 @@ function tryReadConfig(cwd, fileName) {
}
}
/**
* Install all express middleware required by LoopBack.
*
* It is possible to inject your own middleware by listening on one of the
* following events:
*
* - `middleware:preprocessors` is emitted after all other
* request-preprocessing middleware was installed, but before any
* request-handling middleware is configured.
*
* Usage:
* ```js
* app.on('middleware:preprocessors', function() {
* app.use(loopback.limit('5.5mb'))
* });
* ```
* - `middleware:handlers` is emitted when it's time to add your custom
* request-handling middleware. Note that you should not install any
* express routes at this point (express routes are discussed later).
*
* Usage:
* ```js
* app.on('middleware:handlers', function() {
* app.use('/admin', adminExpressApp);
* app.use('/custom', function(req, res, next) {
* res.send(200, { url: req.url });
* });
* });
* ```
* - `middleware:error-loggers` is emitted at the end, before the loopback
* error handling middleware is installed. This is the point where you
* can install your own middleware to log errors.
*
* Notes:
* - The middleware function must take four parameters, otherwise it won't
* be called by express.
*
* - It should also call `next(err)` to let the loopback error handler convert
* the error to an HTTP error response.
*
* Usage:
* ```js
* var bunyan = require('bunyan');
* var log = bunyan.createLogger({name: "myapp"});
* app.on('middleware:error-loggers', function() {
* app.use(function(err, req, res, next) {
* log.error(err);
* next(err);
* });
* });
* ```
*
* Express routes should be added after `installMiddleware` was called.
* This way the express router middleware is injected at the right place in the
* middleware chain. If you add an express route before calling this function,
* bad things will happen: Express will automatically add the router
* middleware and since we haven't added request-preprocessing middleware like
* cookie & body parser yet, your route handlers will receive raw unprocessed
* requests.
*
* This is the correct order in which to call `app` methods:
* ```js
* app.boot(__dirname); // optional
*
* app.installMiddleware();
*
* // [register your express routes here]
*
* app.listen();
* ```
*/
app.installMiddleware = function() {
var loopback = require('../');
/*
* Request pre-processing
*/
this.use(loopback.favicon());
// TODO(bajtos) refactor to app.get('loggerFormat')
var loggerFormat = this.get('env') === 'development' ? 'dev' : 'default';
this.use(loopback.logger(loggerFormat));
this.use(loopback.cookieParser(this.get('cookieSecret')));
this.use(loopback.token({ model: this.models.accessToken }));
this.use(loopback.bodyParser());
this.use(loopback.methodOverride());
// Allow the app to install custom preprocessing middleware
this.emit('middleware:preprocessors');
/*
* Request handling
*/
// LoopBack REST transport
this.use(this.get('restApiRoot') || '/api', loopback.rest());
// Allow the app to install custom request handling middleware
this.emit('middleware:handlers');
// Let express routes handle requests that were not handled
// by any of the middleware registered above.
// This way LoopBack REST and API Explorer take precedence over
// express routes.
this.use(this.router);
// The static file server should come after all other routes
// Every request that goes through the static middleware hits
// the file system to check if a file exists.
this.use(loopback.static(path.join(__dirname, 'public')));
// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
this.use(loopback.urlNotFound());
/*
* Error handling
*/
// Allow the app to install custom error logging middleware
this.emit('middleware:error-handlers');
// The ultimate error handler.
this.use(loopback.errorHandler());
};
/**
* Listen for connections and update the configured port.

View File

@ -197,6 +197,102 @@ describe('app', function() {
});
});
describe('installMiddleware()', function() {
var app;
beforeEach(function() { app = loopback(); });
it('installs loopback.token', function(done) {
app.models.accessToken = loopback.AccessToken;
app.installMiddleware();
app.get('/', function(req, res) {
res.send({ accessTokenId: req.accessToken && req.accessToken.id });
});
app.models.accessToken.create({}, function(err, token) {
if (err) done(err);
request(app).get('/')
.set('Authorization', token.id)
.expect(200, { accessTokenId: token.id })
.end(done);
});
});
it('emits "middleware:preprocessors" before handlers are installed',
function(done) {
app.on('middleware:preprocessors', function() {
this.use(function(req, res, next) {
req.preprocessed = true;
next();
});
});
app.installMiddleware();
app.get('/', function(req, res) {
res.send({ preprocessed: req.preprocessed });
});
request(app).get('/')
.expect(200, { preprocessed: true})
.end(done);
}
);
it('emits "middleware:handlers before installing express router',
function(done) {
app.on('middleware:handlers', function() {
this.use(function(req, res, next) {
res.send({ handler: 'middleware' });
});
});
app.installMiddleware();
app.get('/', function(req, res) {
res.send({ handler: 'router' });
});
request(app).get('/')
.expect(200, { handler: 'middleware' })
.end(done);
}
);
it('emits "middleware:error-handlers" after all request handlers',
function(done) {
var logs = [];
app.on('middleware:error-handlers', function() {
app.use(function(err, req, res, next) {
logs.push(req.url);
next(err);
});
});
app.installMiddleware();
request(app).get('/not-found')
.expect(404)
.end(function(err, res) {
if (err) done(err);
expect(logs).to.eql(['/not-found']);
done();
});
}
);
it('installs REST transport', function(done) {
app.model(loopback.Application);
app.set('restApiRoot', '/api');
app.installMiddleware();
request(app).get('/api/applications')
.expect(200, [])
.end(done);
});
});
describe('listen()', function() {
it('starts http server', function(done) {
var app = loopback();