Creating an MVC Express.js Application (Part 2): Middleware and Configuration
Previously, in an earlier installment we discussed some initial considerations for creating an application in Express.js following the Model View Controller (MVC) design pattern. We’ll pick up where we left off in what follows. The focal point will center around middleware and configuration…
Middleware
One of the things that we are going to want to implement in our application is middleware. There is a pretty good list of Express.js middleware in the Express.js project. Middleware is an important component of Express.js applications. You couple probably think of a middleware function or method as a function that runs on every request/response cycle at whatever point you want to specify. For example, if you wanted to see if the current user who is making the request is authenticated on every single request, you might have this authentication check run in a middleware function before issuing the response. That’s just one example, but there are many other pieces of functionality that you can run within middleware functions.
So let’s add some of the common Express.js middlewares. One useful middleware utility that we can use is a logging component. This will give us information about all of the requests made as our application runs. Express.js uses something called Morgan to accomplish this.
To add middleware, we’re going to want to add it to our package.json file as a dependency. So let’s update our package.json file to look like the following
{
"name": "MVC-Express-Application",
"description": "An Express.js application using the MVC design pattern...",
"version": "0.0.1",
"dependencies": {
"express": "4.4.4",
"express-handlebars": "1.1.0",
"morgan": "1.1.1",
}
}
Don’t forget that we have to install our new module as well. Fortunately, Node.js and npm make this easy. All we have to do is run $ npm install again and all of our packages will be updated…
$ npm install
Now that our dependency is installed, we need to add a reference to it in our main application file…
var logger = require('morgan');
Let’s add the following lines of code to our main app.js file…
/* Morgan - https://github.com/expressjs/morgan
HTTP request logger middleware for node.js */
app.use(logger({ format: 'dev', immediate: true }));
Now if we run our application and look at our CLI window we can see all the requests being output on every request response cycle. And just like that, we have made use of our first middleware.
We will also want a utility to log any errors that occur while we are doing development. So let’s add an error handling utility to our package.json file…
{
"name": "MVC-Express-Application",
"description": "An Express.js application using the MVC design pattern...",
"version": "0.0.1",
"dependencies": {
"express": "4.4.4",
"express-handlebars": "1.1.0",
"morgan": "1.1.1",
"errorhandler": "1.1.1"
}
}
After we run $npm install again to install the error handling module, we again need to add a reference to it…
var errorHandler = require('errorhandler');
Now we can also add the following code to our main application file as well…
/* errorhandler - https://github.com/expressjs/errorhandler
Show errors in development. */
app.use(errorHandler({ dumpExceptions: true, showStack: true }));
We’d probably want to comment this out if we were ever to move our application into a production environment, but for development this is a very handy thing to have for debugging because it can tell us where, when, and how any errors in our application are occurring.
We are not just limited to using middleware that Express.js provides. We can also create our own as well. Let’s add a directory called “utilities” to our project and put a Middleware.js file in this folder.
We will want to make sure that we include a reference to this file in our main application file.
var Middleware = require('./utilities/Middleware');
What can we add to our Middleware.js file? Well, whatever we want really. For example, we can add something that will check to see if there is a set value in the query string and tell our application to show a notification depending what is set. Notifications such as “Profile updated successfully” or “There was an error uploading the file” or other relevant messages are a very important part of a good user-experience in any application. So our application is going to need these as well and using a middleware function to handle this aspect of functionality seems like a decent approach.
Recall that previously we had appended a “pageInfo” object to the response pass to our views. We will utilize this same approach here and add a “notifications” property to this object. Because the middleware runs *before* the controllers that handle our routes, we can initialize the pageInfo property here instead…
exports.AppendNotifications = function(request, response, next) {
response.pageInfo = {};
response.pageInfo.notifications = {};
if(request.param('success')) {
response.pageInfo.notifications.success = "Success!"
}
else if (request.param('error')){
response.pageInfo.notifications.error = "Sorry, an error occured"
}
next();
};
Notice the next(); function at the end of our custom middleware function. This is a common function utilized in middleware implementations. Basically all it does is say “go to the next middleware function, if any.” If there are no more middleware functions to run, execution of the application will just continue on as normal. This way, you can group middleware functions together to run sequentially in the order that you want to specify.
We can also add additional properties on this object e.g. like one to store a message with specific information about the event that occurred. So we’ll add a message property to the notifications object…
exports.AppendNotifications = function(request, response, next) {
response.pageInfo = {};
response.pageInfo.notifications = {};
response.pageInfo.notifications.message = '';
if(request.param('message')) {
response.pageInfo.notifications.message = request.param('message');
}
if(request.param('success')) {
response.pageInfo.notifications.success = "Success!"
}
else if (request.param('error')){
response.pageInfo.notifications.error = "Error!"
}
next();
};
Now we can add our middleware to our main application file, just as we did with the Express.js proved middleware…
app.use(Middleware.AppendNotifications);
Now that we have our middleware in place we’ll need to update our views to be able to show the notifications. Fortunately, we can add something to show these notifications in our Main.handlebars layout…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<title>{{ title }}</title>
</head>
<body>
<div class="notifications">
{{#if notifications.success}}
<div class="success">
{{ notifications.success }} {{ notifications.message }}
</div>
{{/if}}
{{#if notifications.error}}
<div class="error">
{{ notifications.error }} {{ notifications.message }}
</div>
{{/if}}
</div>
{{{body}}}
</body>
</html>
This uses the conditional {{#if }} syntax that the Handlebars.js templating engine provides. This is one of the built-in helpers of Handlebars. You can read more about conditionals and other helpers here.
Now if you navigate to one of our routes and add the query string to the end e.g. http://localhost:1337/?success=true or http://localhost:1337/other?error=true we can see the notification appear. We can also add a message parameter as well e.g. http://localhost:1337/?success=true&message=User added to database. In the normal flow of application, we would usually do a redirect with these parameters after performing some action depending on the outcome but we don’t really have that functionality in our application yet so to see the notifications we just have to add them end of of our URL.
We will use middleware more extensively as the development of our application matures. But for now this illustration shows how middleware can be implemented in useful ways.
Now that we’ve added a spot for notifications, it might be a good idea to add a little bit of style to those notifications. Recall earlier that in our app.js file we had added the following line…
app.use(express.static(path.join(__dirname, 'static')));
This was, if you recall, a way set a directory to serve up some static files from. In this case, we’d want to serve up a CSS file to add a bit of styling in our app. So in this “static” directory create a “css” folder and create a style.css file in tie “css” folder. In this file add the following…
.notifications .success {
padding: 5px;
border: 1px solid #090;
color: #090;
background-color: #9fc;
}
.notifications .error {
padding: 5px;
border: 1px solid #900;
color: #900;
background-color: #fc9;
}
This will add some styling to our notifications. Of course we’ll also have to update our Main.handlebars layout with a reference to this CSS file in the <head> section…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link href="/css/style.css" rel="stylesheet">
<title>{{ title }}</title>
</head>
<body>
<div class="notifications">
{{#if notifications.success}}
<div class="success">
{{ notifications.success }} {{ notifications.message }}
</div>
{{/if}}
{{#if notifications.error}}
<div class="error">
{{ notifications.error }} {{ notifications.message }}
</div>
{{/if}}
</div>
{{{body}}}
</body>
</html>
Now if you add the success or error and/or message query string(s) to the end of any of our routes you will see the same behavior as before only this time with some slick styling for our notifications! This static directory can be used to serve up any other file type that we might need (JavaScript files, images, etc). We just need to add the correct path reference in the layouts or our individual views.
This notifications piece is a great candidate to be a partial view. We looked at partial views earlier on. So we can move this piece…
<div class="notifications">
{{#if notifications.success}}
<div class="success">
{{ notifications.success }} {{ notifications.message }}
</div>
{{/if}}
{{#if notifications.error}}
<div class="error">
{{ notifications.error }} {{ notifications.message }}
</div>
{{/if}}
</div>
into its own view called Notifications.handlebars and put it in the “partials” directory. Then we can update the Main.handlebars layout…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link href="/css/style.css" rel="stylesheet">
<title>{{ title }}</title>
</head>
<body>
{{> Notifications}}
{{{body}}}
</body>
</html>
Now we’ll shift gears and talk about configuration, which is another component that is important to any well-structured application.
Configuration
If you have used any framework in any language — such as Laravel (PHP) or Django (Python) — you know that it is often a good idea to have a configuration file where you can store application variables that will remain constant throughout the application. These sorts of settings include things like database names, connection strings, root URLs, ports, or anything else that you want to utilize. It will also give you a place where you can easily make changes to settings when moving from one environment to another, e.g. when moving from your development environment to production
So we’ll want to create a config.js file for our application as well. Create a config.js file and place it in the main top-level project folder. In config.js place the following code
var config = {};
config.development = {
application: {
port: 1337
}
};
config.production = {
application: {
port: 80
}
};
config.environment = 'development';
module.exports = config;
And we’ll need to make sure that we include a reference to our config file in our main application file.
var config = require('./config');
So, for example, if we do something like changing the following line in our main application file from…
app.set('port', 1337);
to
app.set('port', config[config.environment].application.port);
we are making use of our configuration file because the value of the port we have set will be looked up in the config file. Now if we ever want to push our application from development to staging to production, the only thing we need to edit is the config.js file because, we have a way to quickly and easily set our “environment”. So if we change that string value from “development” to “production,” all of the variables within the object will be switched over across our application. The rest of the application will remain unchanged.
The great thing about this too is that as we add more features and functionality to our application, we can store the needed values for these in our config.js file. This way our application will scale well as it grows and progresses on. Other values important in an application such as database connection strings, credentials, SMTP servers, and strings used for creating hashes and tokens can all be stored in a configuration file. At the end of it all, our config.js file might end up looking more like the following…
var config = {};
config.development = {
database: {
name: 'MVCApplication',
host: 'localhost',
port: '27017',
credentials: '' // username:password@
},
smtp: {
username: "username",
password: "password",
host: "smtp.gmail.com",
port: 587,
ssl: false
},
application: {
port: 1337,
cookieKey: '8YQM5GUAtLAT34'
}
};
config.production = {
database: {
name: 'proddb',
host: 'localhost',
port: '8080',
credentials: 'admin:password@' // username:password@
},
smtp: {
username: "username",
password: "password",
host: "smtp.yourmailserver.com",
port: 25,
ssl: false
},
application: {
port: 80,
cookieKey: '5SCjWfsTW8ySul'
}
};
config.environment = 'development';
module.exports = config;
This is one way to do configuration. Keep in mind that it’s not the only way and there are many other ways you could implement a configuration component in your application. It will probably often come down to a matter of personal preference. The important thing is that you do it in some manner or another to give your application a greater degree of flexibility as you move between environments for development, test, and production. You’ll be glad that you did and you’ll thank yourself later.
Summary
Overall, in this section we looked at 2 important aspects of creating an Express.js application: middleware and configuration. In upcoming explorations, we’ll take a look at some more advanced templating with our views as well as data access and authentication. But for now, it’s good to digest this information in small portions. So feel free download the files below and play around with application configuration and middleware. Remember to run…
$ npm install
after you download to install dependencies.
Download Files Express.js, Handlebars.js, JavaScript, Model View Controller (MVC), Node.js





0 Responses to Creating an MVC Express.js Application (Part 2): Middleware and Configuration