Search code examples
asynchronousnode.jsbefore-filter

In a node.js application, how can I asynchronously achieve the effect of a rails controller before_filter?


I have a node.js Express application with a basic user authentication system where the session is stored in redis. I'd like to write and re-use a current_user() function that populates a JSON representation of the logged in user (if there is one) in a current_user variable. Here is the code to retrieve the user:

if( req.cookie('fingerprint') ) {
  redis_client.get("users:fingerprint:"+req.cookie("fingerprint"), function(err,id) {
    redis_client.get("users:id:"+id, function(err,user) {
      current_user = JSON.parse(user);
    })
  })
}

if I only wanted to use this once, I could put a res.render call after that current_user line, but I'd like to populate the current_user variable for all controllers and actions.

I'm new to node, so there's probably a fundamental concept I'm missing here...but basically I need a way to return the current_user variable from above in a synchronous context or achieve the same effect asynchronously. For example,

app.get('/', function(req,res) {
  current_user = current_user();
  res.render('home', {layout: "layout.ejs", locals: {current_user: current_user}})
})

Thanks.


Solution

  • Express routes accept a third argument: next, this allows you to pass control to the next matching route. You could use this to build up before filters based on routes, like:

    app.get('/admin', function(req, res, next){
      if(authenticated_user()) {
        req.user = get_user();
        next(); 
      }
      else // prompt for login
    });
    
    app.get('/admin/:id', function(req, res){
      // foo
    }
    

    Hope this helps, for more information see Passing Route Control in the official Express guide

    update

    A DRYer way to achieve the same using the oh-so-cool Route Middleware

    function checkAuthentication(req, res, next){
      if(authenticated_user()) {
        req.user = get_user();
        next(); 
      }
      else // prompt for login
    }
    
    app.get('/admin/:id', checkAuthentication, function(req, res){
      // foo
    });