Book Image

Building Scalable Apps with Redis and Node.js

By : Joshua Johanan
Book Image

Building Scalable Apps with Redis and Node.js

By: Joshua Johanan

Overview of this book

Table of Contents (17 chapters)
Building Scalable Apps with Redis and Node.js
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Setting up a config file for our app


Currently, our app runs off of whatever is in the app.js file. If you want to change how the application runs, you will need to edit app.js. This is not very maintainable. As a simple example, what if our cookie secret changes? What happens when we only update one of the references to the cookie secret? Let's say our app grows and the secret is referenced in two other middleware. This will create a lot of pain and waste time tracking down weird bugs in the code. What we need is a config file to store all the application's settings.

The first thing is to create a file named config.js in the root of our app and add this to the file:

var config = {
  port: 3000,
  secret: 'secret',
  redisUrl: 'redis://localhost',
  routes: {
    login: '/login',
    logout: '/logout'
  }
};

module.exports = config;

We are creating an object and then returning it when this file is required. We have the port, cookie secret, Redis URL, and simple route map in our config. We now have to go find where all of these are used, and then update the code.

Route mapping

A route map allows us to use a programmable name for a specific URL. Our new config does this for login and logout. A quick check of our application shows that we are using the string '/login' in four different places. Let's all make it in one place.

We will do this by creating another piece of middleware. Any backend file can get access to this by loading the config module with require(), but the templates do not have this ability. Also, if they did, we do not want to put a boilerplate requirement at the top of every view template. This is where our new middleware comes in. Add a reference at the top of the utitlities.js file present in the middleware folder, and create a new function in the file.

var config = require('../config');
//the other functions or you could put this at the top
exports.templateRoutes = function templateRoutes(req, res, next){
  res.locals.routes = config.routes;

  next();
};

We can see that this just adds the routes object from config to res.locals. Every template will now be able to use the login and logout routes.

Now, add it to the middleware stack. Thinking about our middleware execution order, we know that it just has to go before any templates render. The first middleware that renders is our app.router, so it must go before this.

app.use(flash());
app.use(util.templateRoutes);

Our app now has a config, so we must find all the references to the various settings.

Updating our app to use the config

The first thing to look at is app.js. We will need to add this object to the scope, so add this line as the last variable declaration:

Var config = require('./config');

Now, we must find each reference to the settings in our config. Let's update the secret.

app.use(cookieParser(config.secret));
app.use(session({
  secret: config.secret,
  saveUninitialized: true,
  resave: true,
  store: new RedisStore(
   {url: config.redisUrl})
  })
  );

We fixed the issue that we had initially posed. The only change that we now need to make is in config.js, and all the secrets will be set.

We can now set up the route map's routes. We will change three of our routes in app.js.

app.get(config.routes.login, routes.login);
app.post(config.routes.login, routes.loginProcess);
app.get(config.routes.logout, routes.logOut);

The app now uses the route map to determine the actual URL to bind to. However, now we have an issue: if we update the route in the config, we have some functions that have hard coded '/login'. This will throw a 404 error. We need to track down all the references to login and logout.

The first reference, utilites.js, present in the middleware folder, is the requireAuthentication function. We will update isAuthenticated to redirect back to config.routes.login.

module.exports.requireAuthentication = function requireAuthentication(req, res, next){
  if (req.session.isAuthenticated) {
    next();
  }else {
    res.redirect(config.routes.login);
  }
};

Next is our index.js present in the routes folder; it is the loginProcess function. We will need to redirect back to login on an auth failure.

//add the config reference
var config = require('../config');
//change the function
function loginProcess(req, res){
  var isAuth = util.auth(req.body.username, req.body.password, req.session);
  if (isAuth) {
    res.redirect('/chat');
  }else {
    req.flash('error', 'Wrong Username or Password');
    res.redirect(config.routes.login);
  }
};

The last two files that we will update are the partials. Each partial file has a hard-coded URL that we will change to use config.route as follows:

  • The user-loggedin.ejs file present in the views/partials folder:Hello <%= user.username %> <a href="<%= routes.logout %>">Logout</a>

  • The user-loggedout.ejs file present in the views/partials folder:<a href="<%= routes.login %>">Login</a>

Here is where our middleware is valuable. Every template will have a route's object straight from the config. We are only using it for login and logout, but a site-wide URL should be here so that you can easily update it. For example, we can change the config.routes login and logout to '/account/login' and '/account/logout', and the app will not break.

Finally, we will update the port that the app listens on. This is in app.js:

app.listen(config.port);