Reputation: 24555
What is the best way to call a function on many but not all requests in a node express app? (An example would be a function which checks if the user is currently logged in)
What I did is to define a module exporting a checkLogin(...)
function and to call this function on each corresponding api-request. E.g.:
Module auth:
module.exports = {
checkLogin: function(req, res, next) {
if (req.session.hasOwnProperty('user')) {
//if the user is logged in we pass through
next();
} else if (req.cookies.user == undefined || req.cookies.pass == undefined) {
res.render('login', { title: 'Login' });
} else {
User.checkLogin(req.cookies.user, req.cookies.pass, true, function(o) {
if (o != null) {
req.session.user = o;
next();
} else {
res.render('login', { title: 'Login' });
return;
}
});
}
}
};
Routes for /index:
//...
var auth = require('../middlewares/auth.js');
//...
router.get('/index', auth.checkLogin, function(req, res) {
//if we passed the auth.checkLogin step we render the index page
res.render('index', {
title: 'Index',
udata: req.session.user
});
});
In another route file:
//...
var auth = require('../middlewares/auth.js');
//...
router.get('/user/someAPICall', auth.checkLogin, function(req, res) {
...
});
Is this the way to go or are there better ways to do that? I could define a middleware function which I could include using app.use(function(){..})
in each route. The problem is that every request for this route would go through this function which is not what I want.
Upvotes: 1
Views: 1025
Reputation: 858
Routers (http://expressjs.com/en/guide/routing.html) are a great way to design your application. You could think of your URL paths as namespaces, and create a router for the namespace that requires user authentication.
Most likely your main /index
page won't require immediate redirecting to login, since it's used for presentation purposes; but if required, then just include the auth.checkLogin
as you did above.
For everything else where you need your user to be authenticated (e.g. everything under /user/*
), you'd better create a scoped router
const router = express.Router();
router.use(auth.checkLogin);
router.get('/someAPICall', fn1, fn2);
router.get('/someOtherAPICall', fn3, fn4);
and then in your parent router or main app, just include the router:
app.use('/user', router);
which is just like defining:
app.use('/user/someAPICall', [auth.checkLogin, fn1, fn2]);
app.use('/user/someOtherAPICall', [auth.checkLogin, fn3, fn3]);
This gives you the advantage of creating modular route handlers - which makes them easier to adjust, reuse, etc. - and at the same time will keep auth.checkLogin
, although always executed when the router is entered, just for the paths defined by the router.
In short, the approach would be: "execute function on all routes inside the router, but not on all the app requests".
If you cannot redesign your routes in this way, then yes, you'll always need to include auth.checkLogin
in handlers list for the paths you only want to use.
Upvotes: 2