Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
controller
Advanced tools
a structural aid for creating express routes.
This code sets up an app with 3 handlers, 4 routes, and some middleware which applies to different handler groups.
var express = require('express');
var controller = require('controller');
var app = express();
var users = controller();
// Define handlers
users.define('secret-stuff', ['sensitive'], function(req, res) {});
users.define('edit-account', ['sensitive'], function(req, res) {});
users.define('view-account', function(req, res) {});
// Define middleware for all 'sensitive' grouped handlers
users.middleware('sensitive', function(req, res, next) {});
// Define middleware for all handlers on this controller
users.middleware(function(req, res, next) {});
// Define middleware for 'view-account'
users.middleware('view-account', function(req, res, next) {})
// Define routes
users.get('/secret-stuff/:id', 'secret-stuff');
users.put('/user/edit/:id', 'edit-account');
users.get('/user/:id', 'view-account');
users.get('/view-user/:id', 'view-account');
// Attach to the app
app.use(users);
Create a new controller by requiring controller and calling it as a function, like this:
var controller = require('controller');
var users = controller();
Then attach it to an instance of express, as if it were middleware:
var app = require('express')();
app.use(users);
// It also works to attach it with a route, which will prefix all of the routes
// in the controller with that path.
app.use('/users/', users);
Controller introduces the idea of middleware groups. This allows to you specify named groups, and apply to middleware to every handler that is labelled with this group. For example, you might have bunch of handlers that require you to be logged in, and some middleware which checks authentication. You could add all of the handlers to the 'require-login' group, and then add your auth middleware to the 'reguire-login' group. This will now apply that middleware to every handler in the group.
In action:
var stuff = controller();
// define handlers with their groups
stuff.define('sensitive-thing', ['require-login'], function(req,res){});
stuff.define('secret-thing', ['require-login'], function(req,res){});
// define middleware for the group
stuff.middleware('require-login', function(req, res, next) {
if (isAuthenticated(req)) {
next();
} else {
res.send(403);
}
})
Special Groups
There are some special groups by default. The first one is all
, which applies
middleware to every action on this controller. Apart from that, every action
name is also a middleware group, so you can add middleware to individual actions
Middleware Ordering
'all'
grouped middleware is executed first.route
or direct
. within the group, middlewares are executed in the
order they were added.Define a handler. A handler is a function that is called as the result of a route being visited. This does not route the handler, it only creates it, ready for routing.
Parameters
name
- the name of the handlergroups
(optional) - the groups to add this handler to, for the purpose of
applying middleware to groups of handlers.handler
- the function that is called when the route is visited.Example
users.define('view', function(req, res) {
res.send(Users.read(req.params.id));
});
users.define('edit', ['require-login'], function(req, res) {
Users.update(req.params.id, req.body);
res.send(200);
});
Define some middleware(s) for a group(s). More than one middleware can be passed, as well as more than one group. If you were to pass two groups and two middlewares, each middleware would be added to both groups.
group
has some special values. 'all'
indicates that the middleware should
apply to every route on this controller. If you pass the name of an action as
the group, the middleware will apply to that action only.
Paramaters
group
- defaults to 'all'
middleware
- middleware to add to group
.Example
users.middleware('auth', function checkAuthd(req, res, next) {
// check some auth
});
// Define some middleware for all routes
users.middleware(function(res, req, next) {});
// Define some middleware for the 'getUser' action
users.middleware('getUser', function(req, res, next) {});
Route a handler. Handlers can be routed at more than one location. Just like express, you can also use this method directly on the controller (see example).
Parameters
method
. The http method, for example 'get'
, 'post'
, 'put'
, etc.path
. The path to route the handler to, in exactly the same format you would
pass to express. You can use a regex, but it will ignore options.prefix
.handlerName
. The name of the handler to route.Example
users.route('get', '/user/:id', 'view');
users.route('post', '/user/:id', 'create');
users.route('put', '/user/:id', 'edit');
// or directly on the controller
users.get('/user/:id', 'view')
users.post('/user/:id', 'create');
users.delete('/user/:id', 'delete');
Directly route a function optionally with some middleware. This is essentially
the same as adding a route directly to express. The difference is that handlers
defined with direct
can be included in the controller's middleware groups, and
will be included in the all
group.
Paramaters
method
. The http method, for example 'get'
, 'post'
, 'put'
, etc.path
. The path to route the handler to, in exactly the same format you would
pass to express. You can use a regex, but it will ignore options.prefix
.middleware/groups
. A bunch of middlewares or groups to add the route to.
These can be mixed and matched, Controller will figure it out.handlerfn
. The handler function to call when the route is visited.Example
var uselessMiddleware = function(req,res,next) { next(); };
users.direct('delete', '/user/:id', uselessMiddleware, 'require-login', function(req, res) {
Users.delete(req.params.id);
res.end();
});
users.direct('get', '/user/do-something', function(req, res) {});
You can mount a controller on another controller like so:
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
:
usersController.define('editUser', ['auth'], function(req, res) { ... });
appController.middleware('auth', function(req, res, next) { ... });
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:
usersController.use('/cats', catController);
appController.use('/users', usersController);
Now, lets say that each of these 3 controllers have one global middleware:
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'
.
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:
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.
FAQs
an action controller for express
The npm package controller receives a total of 296 weekly downloads. As such, controller popularity was classified as not popular.
We found that controller demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.