controller
Advanced tools
Comparing version 0.4.2 to 0.5.0
@@ -36,22 +36,21 @@ var isRegExp = require('util').isRegExp; | ||
return route.method === req.route.method | ||
&& route.path === req.route.path; | ||
&& route.path === req.route.path | ||
&& route.self === self; | ||
}); | ||
if (route) req.action = route.action; | ||
if (route) { | ||
req.action = route.action; | ||
req._action = self.actions[req.action]; | ||
} | ||
var scope = ['all']; | ||
if (req.action) { | ||
scope = scope.concat(self.actions[req.action].groups); | ||
if (req._action) { | ||
scope = scope.concat(req._action.groups); | ||
scope.push(req.action); | ||
} | ||
var inScope = function(group) { return ~scope.indexOf(group); }; | ||
var key = scope.join(','); | ||
if (!self.chainCache[key]) { | ||
self.chainCache[key] = _.chain(self.middlewares) | ||
.filter(function(mw) { return mw.scope.some(inScope) }) | ||
.sortBy(function(mw) { return scope.indexOf(_.find(mw.scope, inScope))}) | ||
.value(); | ||
self.chainCache[key] = collectMiddlewares.call(self, scope); | ||
req.route.callbacks = _.reject(req.route.callbacks, function(mw) { | ||
return !!mw.scope; | ||
return !!mw.scope && mw.self == self; | ||
}); | ||
@@ -68,5 +67,48 @@ | ||
Controller.prototype.middleware = function middleware() { | ||
function collectMiddlewares(scope) { | ||
var inScope = function(group) { return ~scope.indexOf(group); }; | ||
return _.sortBy( | ||
_collectMiddlewares.call(this, scope), | ||
function(mw) { return scope.indexOf(_.find(mw.scope, inScope)) } | ||
); | ||
} | ||
function _collectMiddlewares(scope, base) { | ||
if (!base) base = []; | ||
if (this.parent instanceof Controller) | ||
base = _collectMiddlewares.call(this.parent, scope, base); | ||
var inScope = function(group) { return ~scope.indexOf(group); }; | ||
return base.concat( | ||
_.chain(this.middlewares) | ||
.filter(function(mw) { return mw.scope.some(inScope) }) | ||
.value() | ||
); | ||
} | ||
Controller.prototype.addSubController = function(route, controller) { | ||
if (typeof route != 'string') { | ||
controller = route; | ||
route = '/'; | ||
} | ||
if (controller instanceof Controller) controller.parent = this; | ||
this.app.use(route, controller); | ||
}; | ||
Controller.prototype.middleware = Controller.prototype.use = | ||
function middleware(route, controller) { | ||
// just assume we're mounting a subcontroller/app to start with... | ||
if (typeof route != 'string' && route.handle) { | ||
controller = route; | ||
route = '/'; | ||
} | ||
if (controller && controller.handle) | ||
return this.addSubController(route, controller); | ||
// oh, not a controller/app? ok, proceed as normal... | ||
var args = _.flatten([].slice.call(arguments), true), | ||
scope = [], fns = [], self = this; | ||
while (args.length) { | ||
@@ -76,2 +118,3 @@ var arg = args.shift(); | ||
} | ||
if (!scope.length) scope.push('all'); | ||
@@ -81,3 +124,4 @@ var isAll = !!~scope.indexOf('all'); | ||
fns.forEach(function(fn) { | ||
Object.defineProperty(fn, 'scope', {value: scope}); | ||
fn.scope = scope; | ||
fn.self = self; | ||
self.middlewares.push(fn); | ||
@@ -100,3 +144,3 @@ }); | ||
var self = this; | ||
this.routes.push({ method: method, path: path, action: action }); | ||
this.routes.push({ method: method, path: path, action: action, self: self}); | ||
this.app[method](path, this._controllerInit, function(req, res, next) { | ||
@@ -149,2 +193,2 @@ if (!self.actions[action]) { | ||
} | ||
})() | ||
})() |
{ | ||
"name": "controller", | ||
"version": "0.4.2", | ||
"version": "0.5.0", | ||
"description": "an action controller for express", | ||
@@ -18,3 +18,3 @@ "main": "lib/controller.js", | ||
"dependencies": { | ||
"express": "~3.2.0", | ||
"express": "~3.4.4", | ||
"underscore": "~1.3.3", | ||
@@ -21,0 +21,0 @@ "methods": "0.0.1" |
@@ -46,2 +46,3 @@ # controller | ||
* [direct](#direct) - directly route a handler function | ||
* [Mounting controllers on controllers & middleware inheritance](#inheritance) | ||
@@ -232,1 +233,92 @@ --- | ||
--- | ||
<a name="inheritance"/> | ||
### Mounting controllers on controllers & middleware inheritance | ||
You can mount a controller on another controller like so: | ||
```javascript | ||
var appController = Controller(); | ||
var usersController = Controller(); | ||
appController.use('/users', usersController); | ||
``` | ||
The path (in this case, `'/users'`) is optional, but it usually makes senses. | ||
Mounting controllers on each other in this way will cause middleware inheritance. | ||
In our above example, this means that `usersController` will inherit groups and | ||
middlewares from `appController`. If I set a global middleware on `appController`, | ||
`usersController` will get it too. This means that, for example, if I have a | ||
group `'auth'` on `appController`, I can use it as normal on `usersController`: | ||
```javascript | ||
usersController.define('editUser', ['auth'], function(req, res) { ... }); | ||
appController.middleware('auth', function(req, res, next) { ... }); | ||
``` | ||
##### Middleware ordering when using inheritance | ||
The run order of middleware is slightly different when utilising inheritance. | ||
Normally, the global middleware runs first, then the middleware in the order | ||
specified on `define`. When utilising inheritance, this is still true, but within | ||
a group, the lowest level of inheritance will run first. | ||
The easiest way to demonstrate this is to show an example. Lets say we have 3 | ||
controllers inheriting from each other, such as this: | ||
```javascript | ||
usersController.use('/cats', catController); | ||
appController.use('/users', usersController); | ||
``` | ||
Now, lets say that each of these 3 controllers have one global middleware: | ||
```javascript | ||
appController.middleware(function(req, res, next) { console.log('app'); next() }); | ||
usersController.middleware(function(req, res, next) { console.log('users'); next() }); | ||
catController.middleware(function(req, res, next) { console.log('meow'); next() }); | ||
``` | ||
Lets also say that each of these 3 controllers have one middleware in a group | ||
called `'auth'`. | ||
```javascript | ||
appController.middleware('auth', function(req, res, next) { console.log('app (auth)'); next() }); | ||
usersController.middleware('auth', function(req, res, next) { console.log('users (auth)'); next() }); | ||
catController.middleware('auth', function(req, res, next) { console.log('meow (auth)'); next() }); | ||
``` | ||
And we have a route which consumes these middlewares: | ||
```javascript | ||
catController.direct('get', '/meow', ['auth'], function(req, res) { | ||
res.end('MEOW'); | ||
}); | ||
``` | ||
When we send a request to `/users/cats/meow`, the output would be as follows: | ||
``` | ||
app | ||
users | ||
meow | ||
app (auth) | ||
users (auth) | ||
meow (auth) | ||
``` | ||
So the middleware group order was: | ||
``` | ||
appController [global] | ||
usersController [global] | ||
meowController [global] | ||
appController [auth] | ||
usersController [auth] | ||
meowController [auth] | ||
``` | ||
The ordering in which lower levels of middleware are called will not change, | ||
regardless of the order they are added in. |
@@ -186,2 +186,26 @@ var assert = require('assert'); | ||
}); | ||
it('should apply grouped middleware with use()', function(done) { | ||
var c = ctrl(); | ||
c.define('action', ['thing'], routestr('thing')); | ||
c.use('thing', makemw('thingmw')); | ||
c.route('get', '/action', 'action'); | ||
req(express().use(c)) | ||
.get('/action') | ||
.expect(200) | ||
.expect('thingmw') | ||
.end(done); | ||
}); | ||
it('should apply global middleware with use()', function(done) { | ||
var c = ctrl(); | ||
c.define('action', ['thing'], routestr('string')); | ||
c.use(makemw('otherthing')); | ||
c.route('get', '/action', 'action'); | ||
req(express().use(c)) | ||
.get('/action') | ||
.expect(200) | ||
.expect('otherthing') | ||
.end(done); | ||
}); | ||
it('should apply global middleware', function(done) { | ||
@@ -211,2 +235,53 @@ var c = ctrl(); | ||
}); | ||
it('should apply global middleware to subcontrollers', function(done) { | ||
var c0 = ctrl(); | ||
var c1 = ctrl(); | ||
c0.use('/stuff', c1); | ||
c1.define('action', ['thing'], routestr('string')); | ||
c0.use(makemw('thingy')); | ||
c1.route('get', '/action', 'action'); | ||
req(express().use(c0)) | ||
.get('/stuff/action') | ||
.expect(200) | ||
.expect('thingy') | ||
.end(done); | ||
}); | ||
it('should apply grouped middleware to subcontrollers', function(done) { | ||
var c0 = ctrl(); | ||
var c1 = ctrl(); | ||
c0.use('/stuff', c1); | ||
c1.define('action', ['thing'], routestr('string')); | ||
c0.use('thing', makemw('thingy')); | ||
c1.route('get', '/action', 'action'); | ||
req(express().use(c0)) | ||
.get('/stuff/action') | ||
.expect(200) | ||
.expect('thingy') | ||
.end(done); | ||
}); | ||
it('should apply grouped middleware to subcontrollers in the correct order', function(done) { | ||
var c0 = ctrl(); | ||
var c1 = ctrl(); | ||
c0.use('/stuff', c1); | ||
c1.define('action', ['thing'], routestr('string')); | ||
c1.use(makemw('mw1')); | ||
c0.use('thing', makemw('mw2')); | ||
c1.use('thing', makemw('mw3')); | ||
c0.use(makemw('mw4')); | ||
c1.route('get', '/action', 'action'); | ||
req(express().use(c0)) | ||
.get('/stuff/action') | ||
.expect(200) | ||
.expect('mw4mw1mw2mw3') | ||
.end(done); | ||
}); | ||
it('should apply middleware in the correct order', function(done) { | ||
@@ -233,2 +308,2 @@ var c = ctrl(); | ||
}) | ||
}) | ||
}) |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
24799
444
323
0
+ Addedbatch@0.5.0(transitive)
+ Addedbytes@0.2.1(transitive)
+ Addedcommander@1.3.2(transitive)
+ Addedconnect@2.12.0(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddebug@0.8.1(transitive)
+ Addedexpress@3.4.8(transitive)
+ Addedfresh@0.2.0(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedkeypress@0.1.0(transitive)
+ Addedmerge-descriptors@0.0.1(transitive)
+ Addedmethods@0.1.0(transitive)
+ Addedmkdirp@0.3.5(transitive)
+ Addedmultiparty@2.2.0(transitive)
+ Addednegotiator@0.3.0(transitive)
+ Addedqs@0.6.6(transitive)
+ Addedraw-body@1.1.2(transitive)
+ Addedreadable-stream@1.1.14(transitive)
+ Addedsend@0.1.4(transitive)
+ Addedstream-counter@0.2.0(transitive)
+ Addedstring_decoder@0.10.31(transitive)
+ Addeduid2@0.0.3(transitive)
- Removedbytes@0.2.0(transitive)
- Removedcommander@0.6.1(transitive)
- Removedconnect@2.7.11(transitive)
- Removedcookie@0.0.5(transitive)
- Removeddebug@4.3.7(transitive)
- Removedexpress@3.2.6(transitive)
- Removedformidable@1.0.14(transitive)
- Removedfresh@0.1.0(transitive)
- Removedmime@1.2.6(transitive)
- Removedmkdirp@0.3.4(transitive)
- Removedms@2.1.3(transitive)
- Removedqs@0.6.5(transitive)
- Removedsend@0.1.00.1.1(transitive)
Updatedexpress@~3.4.4