eol
eol

Reputation: 24555

Express app - Execute function on many but not all requests

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

Answers (1)

Mihai Potra
Mihai Potra

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

Related Questions