Express.js – 9bit Studios https://9bitstudios.com Web Design, Themes, & Applications Sun, 13 Aug 2017 14:41:43 +0000 en-US hourly 1 https://wordpress.org/?v=4.8.2 Debugging Node.js Applications with Node Inspector https://9bitstudios.com/2015/10/debugging-node-js-applications-with-node-inspector/ https://9bitstudios.com/2015/10/debugging-node-js-applications-with-node-inspector/#respond Thu, 29 Oct 2015 13:46:46 +0000 https://9bitstudios.com/?p=1087 Debugging is an important part any sort of application development. If you have errors or unexpected results occurring in your code you need to be able to step through your code and find where things are going awry. Thus it is very important that you are able to see what is happening at specific times when your code is executing. There are some IDEs (integrated development environments like Visual Studio or Eclipse) where debugging for the native application language like C# or Java is all built right into the tools and you don’t have to do anything to set it up. At the time of this writing in the later part of the year 2015, there are a few IDEs such as WebStorm and Komodo IDE that natively support Node.js debugging but this is often the exception rather than the rule (at present). Node.js, being a younger and relatively more immature platform often does not have debugging for it natively implemented in most IDEs yet. Fortunately, there are often plugins available that will enable Node.js debugging within the IDE. Node.js tools for Visual Studio 2012 and 2013 is one example. Nodeclipse is a plugin that will enable Node.js debugging capabilities in Eclipse.

Because there are so many different development environments and workflows that different developers have different preferences for we won’t look at debugging Node.js applications in a specific IDE. But we will look at a specific debugger called Node Inspector. There are other Node.js debuggers out there and if you want to use another debugger that is fine. You would just have to look at the docs for that particular debugger. It should be noted that Node Inspector works in Chrome and Opera only. You have to re-open the inspector page in one of those browsers if another browser is your default web browser (e.g. Safari or Internet Explorer). This is another indicator that shows widespread support for many things in and within Node.js is not entirely quite there just yet. So much of the Node.js module ecosystem is community driven, which has very noticeable pros and cons. The upside to this it is that there are a lot of awesome components of functionality that you can leverage via installation with a simple $ npm install of a module. The downside of this environment is that support and/or consistency for bug fixes and releases can vary quite a bit depending on who’s module(s) you are using. Just as a personal opinion, I find that on the whole the positives outweigh the negatives when it comes to open source software. I would much rather take this scenario over, say, a behemoth corporation owning and managing all of the releases that might seem more “professional” in its support and maintenance (as opposed to hobby/side-project code). But developing in and for open source applications is definitely far from perfect.

But all that aside, let’s get back to fun with Node.js debugging. Node Inspector works almost exactly as the Google Chrome Developer Tools. If you are not entirely familiar with Google Chrome’s developer tools read the DevTools overview to get started. Dev Tools can be used to set breakpoints in your application that halt the execution of the code when a certain statement (or statements) are reached. From there you can examine the state of particular objects to see what values they contain at that point in time. You can then step through your code moving from one statement to the next to see how the values change. If this all seems a little bit confusing at this point, not to worry. We will revisit this a bit later when we actually take on the task of debugging our application. But first we need to install the stuff we need to get debugging up and going.

Installing Node Inspector

To install Node inspector we will use the npm utility to install Node Inspector from npm.

$ sudo npm install -g node-inspector

Note: Windows 8.1 Users: At the time of this writing in the later part of 2015 for Windows 8.1 I had to omit installing an optional dependency which apparently breaks the install using npm. The way that you do this is by setting the –no-optional flag…

$ npm install -g node-inspector --no-optional

That should get it working for you. To check that it installed correctly you can always run

$ node-debug --version

which should output the version number for you without any error messages.

Sample Application

For our application we will use a sample API that I often utilize for demonstrating Node.js applications that uses Express.js as an application framework. If you are not familiar with Express there is an introduction to Express here. If you need a quick refresher on Node.js by any chance you can read A Node.js Primer. For a more in-depth look at Express.js, there is also an ongoing series entitled Creating an MVC Express.js Application.

We will start out by creating a package.json file and placing the following code within it…

{
    
    "name": "Node.js-API",
    "description": "An API in Node.js...",
    "version": "0.0.1",
    
    "repository": {
        "type": "",
         "url": ""
    },
    "dependencies": {

        "express": "4.4.4",
        "express-session": "1.5.1",
        "basic-auth": "1.0.3",
        "cookie-parser": "1.3.1",
        "body-parser": "1.4.3",
        "hbs": "3.1.0",
        "morgan": "1.1.1",
        "method-override": "2.0.2",
        "errorhandler": "1.1.1"
    }

}

We then run

$ npm install

to install all the dependencies.

Next, create a file called server.js with the following code…

var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var logger = require('morgan');
var methodOverride = require('method-override');
var errorHandler = require('errorhandler');
var http = require('http');
var path = require('path');
var app = express();
app.set('port', 1337);

app.set('view engine', 'html');
app.engine('html', require('hbs').__express);

/* Morgan - https://github.com/expressjs/morgan
 HTTP request logger middleware for node.js */
app.use(logger({ format: 'dev', immediate: true }));

/* cookie-parser - https://github.com/expressjs/cookie-parser
 Parse Cookie header and populate req.cookies with an object keyed by the cookie names. */
app.use(cookieParser('SECRETCOOKIEKEY123'));

/* body-parser - https://github.com/expressjs/body-parser 
Node.js body parsing middleware. */
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

/* method-override - https://github.com/expressjs/method-override
 Lets you use HTTP verbs such as PUT or DELETE in places where the client doesn't support it. */		    
app.use(methodOverride());

app.use(express.static(path.join(__dirname, '')));

/* errorhandler - https://github.com/expressjs/errorhandler
 Show errors in development. */
app.use(errorHandler({ dumpExceptions: true, showStack: true }));

// send app to router
require('./router')(app);

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

Next create a file called router.js with the following code…

// Routes
module.exports = function(app){ 
    // index.html
    app.get('/', function(request, response){
        response.render('index', {});
    }); 
    // API
    var artists = [
        { id: 1, name: 'Notorious BIG', birthday: 'May 21, 1972', hometown: 'Brooklyn, NY', favoriteColor: 'green' },
        { id: 2, name: 'Mike Jones', birthday: 'January 6, 1981', hometown: 'Houston, TX', favoriteColor: 'blue' },
        { id: 3, name: 'Taylor Swift', birthday: 'December 13, 1989', hometown: 'Reading, PA', favoriteColor: 'red' }
    ];

    // GET /api/artists
    app.get('/api/artists', function(request, response){
        response.json(artists);
    });


    // GET /api/artist/:id
    app.get('/api/artist/:id', function(request, response){
        var id = request.params.id;
        var obj = artists[id - 1]; 
        response.json(obj);
    });

};

And lastly we will create an index.html file as a homepage…

<!DOCTYPE html>
<html>
<head>
    <title>App</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
        
    <h1>Node.js Example</h1>
	
	<p>A basic example showing an API in Node.js</p>
	
	<p>Go to <a href="/api/artists">/api/artists</a> to view a JSON response of all artists</p>
	
	<p>Go to <a href="/api/artist/1">/api/artist/1</a> or <a href="/api/artist/2">/api/artist/2</a> to view a JSON response of an individual artist</p>
	
</body>
</html>

Now to run the application you simply have to open a terminal /command window and type the following…

$ node server

You should see a message logged to the screen that the Express server is running on port 1337. Press Ctrl+C or Cmd+C to quit.

Debugging With Node Inspector

To debug our application with Node Inspector, instead of running our application with the “node” command as we did above we can run it with node-debug instead…

$ node-debug server

This will open up a tab in your browser. As mentioned previously it will look a lot like Google Chrome’s dev tools because it uses a lot of the same structure from dev tools. By default the tools should stop the execution of the code at the first statement of the application as is shown.

Debugging Node.js applications

You can see all of the files that are present in our application (as well as the modules we have installed on the left).

To set some breakpoints you can click on the line numbers in the code like as is shown in the following screenshot.Try placing a breakpoint inside one of the routes (the “/api/artists” route) on the response statement. Next in your browser navigate to the “/api/artists” route. If all goes well script execution should stop on that statement. From here you can hover over different objects such as the request and the response object and and examine the different properties on them.

Debugging Node.js applications

Obviously this is a simple example. But as your application gets more complex debugging can be a powerful tool to track down errors that occur in Node.js applications. You could even use the “step into” button to step through individual modules as they are used. Hopefully this simple guide has helped you get on your way.

Until next time, happy debugging!

]]>
https://9bitstudios.com/2015/10/debugging-node-js-applications-with-node-inspector/feed/ 0
Basic Authentication in Node.js Express Applications and APIs https://9bitstudios.com/2015/10/basic-authentication-in-node-js-express-applications-and-apis/ https://9bitstudios.com/2015/10/basic-authentication-in-node-js-express-applications-and-apis/#respond Thu, 15 Oct 2015 14:49:43 +0000 https://9bitstudios.com/?p=1077 In the past we have looked at basic access authentication using the Slim PHP framework. In the context of an HTTP transaction, basic access authentication is a method for an HTTP user agent to provide a user name and password when making a request. It is an easy way to secure different parts of your application by prompting the user to enter credentials before you serve up the response, be it a webpage of HTML or some XML or JSON at an API endpoint. It looks something like the following in browsers…

Basic Authentication

All you need to do is send WWW-Authenticate headers to get this prompt to appear. You can also specify a realm that allows you to have different “groupings” of authentication. If a user successfully enters the their credentials for one realm they will not have to re-enter their credentials for other pages or routes protected under basic authentication in the same realm. This will last for the duration of the user’s session. However, if he or she tries to access a route under a different realm he/she will have enter credentials again (which can be the same credentials or a different name/password combination). In this manner you can have different authentications for different places within your website or web application.

When the user enters credentials, these credentials are encoded with BASE64 encoding and sent to the server. They are not encrypted or hashed in any way. Thus, it would be pretty easy for an individual on the same network to view and decode these credentials (and then possibly use them for malevolent purposes). This is what is known as a man in the middle attack (MitM) and it is one of the common security vulnerabilities that developers need to be cognisant of. You could, of course, add an additional component to security such as sending an additional hash in a cookie that can be decoded on the server. However, in order for this to be effective both the server and the client need to have a private key that is known on both ends and is not sent over the wire. Getting this key from the server to the client requires an additional step of involvement for users. Thus, probably the most straightforward way of using basic authentication in a secure manner is to use TLS/SSL and have all requests between server and client be over https://.

Whatever you decide to do, basic authentication can be a decent solution for security if it is used properly.

So in what follows we will take a look and see how we can implement this in a Node.js application that uses Express.js as an application framework. Before looking at the following section, it might be a good idea to be familiar with Express.js by reading the introduction to Express and be familiar with Node.js as well. Another article entitled A Node.js Primer will help you with that. For a more in-depth look at Express.js, there is also an ongoing series of posts that discusses how to create an MVC Express.js Application that covers many different aspects of using Express.js.

Let’s take a look and see how we might implement this…

Setting Up

Like with a lot of things in Node.js working with Node.js we will first create a package.json file that will be used to install our dependencies for this exercise. So create a package.json file and in it place the following code…

{
    
    "name": "Node.js-API",
    "description": "An API in Node.js...",
    "version": "0.0.1",
    
    "repository": {
        "type": "",
         "url": ""
    },
    "dependencies": {

        "express": "4.4.4",
        "express-session": "1.5.1",
        "basic-auth": "1.0.3",
        "cookie-parser": "1.3.1",
        "body-parser": "1.4.3",
        "hbs": "3.1.0",
        "morgan": "1.1.1",
        "method-override": "2.0.2",
        "errorhandler": "1.1.1"
    }

}

As can be seen we in our dependency list we will be using the basic-auth module from npm

Now that we have our package.json file created, we should install everything by opening a shell and running…

$ npm install

This will download all of our modules and place them in a folder called “node_modules”

Next, create a file called server.js and in it place the following code…

var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var logger = require('morgan');
var methodOverride = require('method-override');
var errorHandler = require('errorhandler');
var http = require('http');
var path = require('path');
var app = express();
app.set('port', 8080);

app.set('view engine', 'html');
app.engine('html', require('hbs').__express);

/* Morgan - https://github.com/expressjs/morgan
 HTTP request logger middleware for node.js */
app.use(logger({ format: 'dev', immediate: true }));

/* cookie-parser - https://github.com/expressjs/cookie-parser
 Parse Cookie header and populate req.cookies with an object keyed by the cookie names. */
app.use(cookieParser('SECRETCOOKIEKEY123'));

/* body-parser - https://github.com/expressjs/body-parser 
Node.js body parsing middleware. */
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

/* method-override - https://github.com/expressjs/method-override
 Lets you use HTTP verbs such as PUT or DELETE in places where the client doesn't support it. */		    
app.use(methodOverride());

app.use(express.static(path.join(__dirname, '')));

/* errorhandler - https://github.com/expressjs/errorhandler
 Show errors in development. */
app.use(errorHandler({ dumpExceptions: true, showStack: true }));

// send app to router
require('./router')(app);

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

We will not go into too much depth on what each of these lines of code do. This file serves as the kickoff point for starting our Node.js Express web application. A lot of these modules are somewhat superfluous at this point but they will definitely prove to be useful later on if you wanted to get into more complex development with APIs so I have gone ahead and included them here. If you are interested in a more in-depth explanation surrounding what each of these lines of code do, be sure to take a look at the creating an MVC Express.js application discussions. Again, we will not be discussing what all of this code does in too much depth. Just know that this is code that will start up a server and run all of the code that will be needed for when HTTP requests are sent to and from some specific routes. We will look at these routes next.

So next create a file called router.js. For our example we will return JSON from the various routes that we set up, but all the same basic authentication implementations would apply if we were returning a webpage of HTML or data in XML format…

var Authentication = require('./utilities/Authentication');

// Routes
module.exports = function(app){ 
    // index.html
    app.get('/', function(request, response){
        response.render('index', {});
    }); 
    // API
    var artists = [
        { id: 1, name: 'Notorious BIG', birthday: 'May 21, 1972', hometown: 'Brooklyn, NY', favoriteColor: 'green' },
        { id: 2, name: 'Mike Jones', birthday: 'January 6, 1981', hometown: 'Houston, TX', favoriteColor: 'blue' },
        { id: 3, name: 'Taylor Swift', birthday: 'December 13, 1989', hometown: 'Reading, PA', favoriteColor: 'red' }
    ];

    // GET /api/artists
    app.get('/api/artists', function(request, response){
        response.json(artists);
    });


    // GET /api/artist/:id
    app.get('/api/artist/:id', Authentication.BasicAuthentication, function(request, response){
        var id = request.params.id;
        var obj = artists[id - 1]; 
        response.json(obj);
    });

};

Notice that for the get all artists route “/artists” this route is open and accessible to anyone, but each individual artist page “/api/artist/:id” with id being the int value of the artist ID, this runs a middleware function called “Authentication.BasicAuthentication.” Middleware in Node.js and Express.js is discussed in this entry about creating an Express.js application. There is also a pretty good exploration of middleware in the aforementioned Slim PHP Basic Authentication tutorial. Different language, same thing conceptually.

We included this middleware function with the statement var Authentication = require(‘./utilities/Authentication’); at the top of our router.js file. We still need to write the code for this functionality, so let’s do that next.

Writing Our Basic Authentication Function

Create a folder called “utilities” and create a file called “Authentication.js” it is here where we will add our basic authentication check …

var basicAuth = require('basic-auth');

exports.BasicAuthentication = function(request, response, next) {

    function unauthorized(response) {
        response.set('WWW-Authenticate', 'Basic realm=Authorization Required');
        return response.send(401);
    };

    var user = basicAuth(request);

    if (!user || !user.name || !user.pass) {
        return unauthorized(response);
    };

    if (user.name === 'foo' && user.pass === 'bar') {
        return next();
    } else {
        return unauthorized(response);
    };
	
};

So as we can see from the code above, we will protect a number of different routes with the name “foo” and the password “bar.” The realm we provided is just called “Authorization Required.” By setting the “www-authenticate” header we will prompt the user to enter credentials

And lastly we can create our index.html which will really only provide some links to the different routes. This index.html will be served up by our server at the home route (“/”)…

<!DOCTYPE html>
<html>
<head>
    <title>App</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
        
    <h1>Node.js Basic Authentication Example</h1>
    <p>A basic example showing basic authentication of an API in Node.js</p>
    <p>Anyone should be able to view <a href="/api/artists">/api/artists</a></p>
    <p>However, individual artist pages such as <a href="/api/artist/1">/api/artist/1</a> or <a href="/api/artist/2">/api/artist/2</a> are protected by basic authentication. Username is foo, password is bar</p>

</body>
</html>

So now we can test out how everything works. Open a command window and run the following…

$ node server

If we go to https://localhost:8080 we should see the content in our index.html file. We can check out the different routes by clicking on the various links. If all is well, we should see that for the get all artists route “/artists” this route is completely accessible with no authentication required, but each individual artist page “/api/artist/:id”, you will be prompted for credentials. So enter the name and password — name: foo, password: bar — to authenticate. Once you enter these credentials you will be able to access other single artist routes as well because you are now authenticated against this realm.

Setting Different Realms

What if we wanted to have a way to set different realms? How would we go about doing this? What we need to do in this instance is we need to write another middleware function that will run before our Authentication.BasicAuthentication middleware function. We then need to pass that custom realm forward into the next middleware function.

To accomplish this we are going to attach this information onto the request object itself. Because JavaScript is a dynamic language we can just extend objects all we want! We can add new properties, new methods, update values, or whatever else. So what we’re going to so is we’re going to create a new function in our “Authentication” module that will return a middleware function. What does this look like? Update our Authentication module with a new “SetRealm” function…

var basicAuth = require('basic-auth');

exports.BasicAuthentication = function(request, response, next) {

    function unauthorized(response) {
        response.set('WWW-Authenticate', 'Basic realm=' + request.authRealm);
        return response.send(401);
    };

    var user = basicAuth(request);

    if (!user || !user.name || !user.pass) {
        return unauthorized(response);
    };

    if (user.name === 'foo' && user.pass === 'bar') {
        return next();
    } else {
        return unauthorized(response);
    };
	
};

exports.SetRealm = function(realm) {
    return function(request, response, next){
        request.authRealm = realm || 'default';	
        return next();
    }
};

Notice that we are dynamically adding a property called authRealm to the request object. The return value of this SetRealm function is a function… a middleware function to be more specific as is identifiable to the call to next(). We are adding a property called authRealm to the request object and then calling next. Notice to that in our “BasicAuthentication” method above we are using this authRealm property to set the basic realm identifier.

Now we can update our router.js file to make use of this new implementation…

var Authentication = require('./utilities/Authentication');

// Routes
module.exports = function(app){ 
    // index.html
    app.get('/', function(request, response){
        response.render('index', {});
    }); 
    // API
    var artists = [
        { id: 1, name: 'Notorious BIG', birthday: 'May 21, 1972', hometown: 'Brooklyn, NY', favoriteColor: 'green' },
        { id: 2, name: 'Mike Jones', birthday: 'January 6, 1981', hometown: 'Houston, TX', favoriteColor: 'blue' },
        { id: 3, name: 'Taylor Swift', birthday: 'December 13, 1989', hometown: 'Reading, PA', favoriteColor: 'red' }
    ];

    // GET /api/artists
    app.get('/api/artists', function(request, response){
        response.json(artists);
    });


    // GET /api/artist/:id
    app.get('/api/artist/:id', Authentication.SetRealm('artist'), Authentication.BasicAuthentication, function(request, response){
        var id = request.params.id;
        var obj = artists[id - 1]; 
        response.json(obj);
    });

    app.get('/api/other', Authentication.SetRealm('other'), Authentication.BasicAuthentication, function(request, response){
        respose.json({ message: 'This is the other route '});
    });

};

Notice that we have added a new route “/api/other.” As we can see we are using our Authentication.SetRealm method and passing in the realm name. This method will return a middleware function that will run in this location. Now if we run our application again we can see that to authenticate against the “/api/artist/:id” routes we need to authenticate with our credentials. But if we try to hit the “/api/other” route we need to authenticate with our credentials again! This is because the realm is different. We can do lots of different types of layers and customizations to protect our web application or API. It can be a good solution for your needs in a lot of different circumstances.

That is basically all there is to implementing basic authentication with Node.js Express applications. You could of course take this and expand upon it with different realms and routes, but the essentials are all there. So feel free to download the demo files below and play around with it. Remember to run $ npm install before you do anything else. And as always, thanks for reading!

Demo Files
]]>
https://9bitstudios.com/2015/10/basic-authentication-in-node-js-express-applications-and-apis/feed/ 0
Creating an MVC Express.js Application (Part 4): Relational Data in MongoDB https://9bitstudios.com/2015/08/creating-an-mvc-express-js-application-part-4/ https://9bitstudios.com/2015/08/creating-an-mvc-express-js-application-part-4/#respond Tue, 04 Aug 2015 18:16:23 +0000 https://9bitstudios.com/?p=1045 In this section we will look at another interesting aspect of creating a web application using Node.js, Express, and MongoDB: referencing other data in the database. MongoDB is part of the NoSQL class of databases (as opposed to the traditional relational databases that have been so prevalent for so long). NoSQL databases store records as documents as opposed to relational databases which store records as rows in tables. Documents in NoSQL databases are basically collections of key value pairs sort of like JSON objects. As the MongoDB documentation describes in the introduction

A record in MongoDB is a document, which is a data structure composed of field and value pairs. MongoDB documents are similar to JSON objects. The values of fields may include other documents, arrays, and arrays of documents.

You can find many articles out on the web discussing the difference between NoSQL databases and relational databases. MongoDB is a solution to a common problem and like with many things it has its advantages and its drawbacks.

But even with their structure, NoSQL database documents still have need to store references to other objects within them (somewhat like foreign keys). We have been creating data models of books in previous examples in this tutorial that have a “title” field, an “author” field, and an “isPublished” field. We have been storing the author as a string value. But really in a real-world application we’d more likely want to store a reference to an author that exists in an authors collection elsewhere. That way we could store additional information about an author or show a collection of books written by the same author. When you start relating and connecting data in this manner your application becomes truly dynamic and useful

Setup

So let’s create an “AuthorModel” and all of the scaffolding to put an “authors” section in the database. Like we’ve done before, we’ll want to follow the same process: define our model schema for our “AuthorModel,” add routes, add controllers, and add views. We will move fairly quickly through this. A lot of what we are doing was covered earlier in this tutorial. If there are any parts that seem unclear, please go back and review the content presented earlier to get a refresher on how this application is being structured.

So let’s start by defining our author schema in our Models.js file. This one will be a bit simpler than our book model schema. All we need to add here is a name. What will be important later on is the author _id value that we can associate with a book as a reference field…

var Author = new mongoose.Schema({
    name: String
});


var BookModel = mongoose.model('Book', Book);
var UserModel = mongoose.model('User', User);
var AuthorModel = mongoose.model('Author', Author);

module.exports = {
    BookModel: BookModel,
    AuthorModel: AuthorModel,
    UserModel: UserModel
};

And let’s continue with adding our author routes to the router.js file making sure to add a refenrece to our soon-to-be-created AuthorsController…

var HomeController = require('./controllers/HomeController');
var BookController = require('./controllers/BookController');
var AuthorController = require('./controllers/AuthorController');

// Routes
module.exports = function(app){
    
    // Main Routes
    
    app.get('/', HomeController.Index);
    app.get('/other', HomeController.Other);   

    // Book Routes
    
    app.get('/books', BookController.Index);
    app.get('/books/add', BookController.BookAdd); 
    app.post('/books/add', BookController.BookCreate); 
    app.get('/books/edit/:id', BookController.BookEdit);
    app.post('/books/edit', BookController.BookUpdate); 
    app.get('/books/delete/:id', BookController.BookDelete);     

    // Author Routes
    
    app.get('/authors', AuthorController.Index);
    app.get('/authors/add', AuthorController.AuthorAdd); 
    app.post('/authors/add', AuthorController.AuthorCreate); 
    app.get('/authors/edit/:id', AuthorController.AuthorEdit);
    app.post('/authors/edit', AuthorController.AuthorUpdate); 
    app.get('/authors/delete/:id', AuthorController.AuthorDelete);  

}; 

Now we can add the respective controllers by creating an AuthorsController. This will look very similar to our BooksController because we are largely needing all the same types of actions (Create, Read, Update, and Delete) as we did with our BookController. The only difference is that in this case we’ll be using our author Models instead of our book models…

var Model = require('../models/Models');
var Validation = require('../utilities/Validation');

exports.Index = function(request, response){

    Model.AuthorModel.find(function(error, result){
        if (error) {
            console.log('Error');
            Validation.ErrorRedirect(response, '/', 'There was an error finding authors in the database');
        } else {
            response.pageInfo.title = 'Authors';
            response.pageInfo.authors = result;
            response.render('authors/Index', response.pageInfo);
        }
    });

};

exports.AuthorAdd = function(request, response){
    response.pageInfo.title = 'Add an Author';
    response.render('authors/AuthorAdd', response.pageInfo);
};

exports.AuthorCreate = function(request, response){ 

    var name = request.body.name;

    if(Validation.IsNullOrEmpty([name])) {
        Validation.ErrorRedirect(response, '/authors', 'Please fill out all fields');
    } else {

        var a = new Model.AuthorModel({ 
            name: name
        });

        a.save(function(error){
            if(error) {
                console.log('Error');
                Validation.ErrorRedirect(response, '/authors', 'There was an error adding the author to the database');
            } else {
                Validation.SuccessRedirect(response, '/authors', 'Author created successfully');
            }
        });
    }
};

exports.AuthorEdit = function(request, response){
    var id = request.params.id;
    
    Model.AuthorModel.findOne({ _id: id }, function(error, result){
        if(error) {
            console.log('Error');
            Validation.ErrorRedirect(response, '/authors', 'There was an error finding an author in the database with this id');
        }
	else {
            if(result) {
                response.pageInfo.title = 'Edit Author';
                response.pageInfo.author = result;
                response.render('authors/AuthorEdit', response.pageInfo);
            } else {
                Validation.ErrorRedirect(response, '/authors', 'There was an error finding an author in the database with this id');
            }
        }
	
    });
}

exports.AuthorUpdate = function(request, response){ 

    var name = request.body.name;

    if(Validation.IsNullOrEmpty([name])) {
        Validation.ErrorRedirect(response, '/authors', 'Please fill out all fields');
    } else {
    
        Model.AuthorModel.update(
            { _id: request.body.id }, 
            {
                name: name
            },
            { multi: true }, 
            function(error, result){
                if(error) {
                    console.log('Error')
                    Validation.ErrorRedirect(response, '/authors', 'There was an error finding an author in the database with this id');
                } else {
                    Validation.SuccessRedirect(response, '/authors', 'Author updated successfully');
                }        
            }
        );
    }
}

exports.Authorelete = function(request, response){ 
    var id = request.params.id;
    Model.AuthorModel.remove({ _id: id }, function(error, result) {
        if(error) {
            console.log('Error');
            Validation.ErrorRedirect(response, '/authors', 'There was an error deleting the author');
        } else {
            Validation.SuccessRedirect(response, '/authors', 'Author deleted successfully');
        }
    });
}

And lastly let’s create our views. Create a new folder in the main directory and call it “authors”. In this folder we can create the Index.handlebars, AuthorAdd.handlebars and AuthorEdit.handlebars views.

Index.handlebars

<ul>
{{#authors}}
    <li>
        <strong>{{name}}</strong> - <a href="/authors/edit/{{ _id }}">Edit</a> <a href="/auhors/delete/{{ _id }}" onclick="return confirm('Are you sure?')">Delete</a>
    </li>

{{ else }}
    <p>There are no authors.</p>

{{/authors}}
</ul>

<a href="/authors/add">Add Author</a>

AuthorAdd.handlebars

<form method="post" action="/authors/add">
    <label>Name</label> <input name="name" type="text" />
    <input type="submit" value="Submit" />
</form>

AuthorEdit.handlebars

<form method="post" action="/authors/edit">
    <input name="id" type="hidden" value="{{ author._id }}" />
    <label>Name</label> <input name="name" type="text" value="{{ author.name }}" />
</form>

This is one of the advantages to building with the model-view-controller design pattern. We are able to quickly add functionality to entirely new data types and all the scaffolding we need to add entries to the database simply by creating a few new files of similar type to others.

Now if we run our application using…

$ node app

we can go to the “/authors” routes and from there add some new authors to the database. These authors are not associated with any books yet, but we’ll change that shortly.

Adding Object References

Now that we have our authors in the db, the next thing we’ll want to do is update our book model schema in our Models.js file to reference an author field since a book object will be associated with an author. As described in the Mongoose documentation here, we can create references to other documents in our schemas. So we can do this like so. Before, our “BookModel” looked like this…

var Book = new mongoose.Schema({
    title: String,
    author: String,
    isPublished: Boolean
});

var Author = new mongoose.Schema({
    name: String
});

with our author stored as a string. We can update this to the following…

var Book = new mongoose.Schema({
    title: String,
    author: { type: mongoose.Schema.Types.ObjectId, ref: 'Author' },
    isPublished: Boolean
});

var Author = new mongoose.Schema({
    name: String
});

So now we have an author as a reference to an author than will be associated with each book.

Of course, now that we have updated our model, we’ll need to update the manner in which we handle things in our controllers because there is a little bit more involved in displaying a book in our views. We are going to have to look up the associated author _id value that exists on the book and pass it into the view along with the other regular book data. It might help to conceptualize things if you delete all of your existing books in the database and start afresh.

As always, we’ll start off small and we’ll work our way up. We’ll start out by working on the controllers and views to add some books with associated authors. Mongoose provides us a method of using promises as a way of retrieving data asynchronously through the exec method (which returns a promise). We can then chain the various function calls together using the then method and they will execute in their proper order. This will become increasingly important as our objects and our associations become more complex. So for our controller to add a book we need to first get all authors, then return the view.

exports.BookAdd = function(request, response){
    Model.AuthorModel.find({}).exec(function(error, result){

        if(error) {
            Validation.ErrorRedirect(response, '/books', 'There was an error getting the author list');
        } else {
            response.pageInfo.authors = result;
        }
    }).then(function(){

        response.pageInfo.title = 'Add a Book';
        response.render('books/BookAdd', response.pageInfo);
    });
};

When we pass in the empty object { } into the exec function Mongoose interprets this to mean “find all” in this case: find all authors.
So we’ve added the authors object to the pageInfo response. So let’s now go and update the view to add a book. We’ll use a <select> box to display a dropdown of a list of authors…

<form method="post" action="/books/add">
    <label>Title</label> <input name="title" type="text" />
    <label>Author</label>

    <select name="author" class="">
	{{#authors}}
	    <option value="{{_id}}">{{name}}</option>
	{{/authors}}
    </select>

    <label>Is Published?</label> <input name="published" type="checkbox" value="published" />
    <input type="submit" value="Submit" />
</form>

If you start the app up and go to the “books/add” route, you should see some of your authors populated in the dropdown. So what we send up to the server when we post the form back is no longer an author string, but rather an author “_id” value. Because we updated our BookModel

Of course, once we create a new book with our new schema we see that once we are redirected back to the “/books” route on successful adding of a book we no longer see our author name but rather our internal ugly MongoDB _id value. So let’s change our home view to show the author rather than this ugly id.

So like with our controller to add a book, we’ll need to get the author of each book so that we can display that author’s name. It wouldn’t seem very efficient to pull down all the authors and then compare the authors in the list for each book. Fortunately, Mongoose gives us a method that will allow us to populate the books we are getting back from the database with the object reference using the populate method. Thus, we’d want to update our Index controller in our BookController.js file to look like the following…

exports.Index = function(request, response){

    Model.BookModel.find({}).populate('author').exec(function(error, result){
        if (error) {
            console.log('Error');
            Validation.ErrorRedirect(response, '/', 'There was an error finding books in the database');
        } else {
            response.pageInfo.title = 'Books';
            response.pageInfo.books = result;
            response.render('books/Index', response.pageInfo);
        }
    });
};

See how we have used the populate method to populate the author field for each book on our book model with the author object. As a result, in our view we have direct access to this author object.

<ul>
{{#books}}
    <li>
        <strong>{{title}}</strong> by: {{ author.name }} - <a href="/books/edit/{{ _id }}">Edit</a> <a href="/books/delete/{{ _id }}" onclick="return confirm('Are you sure?')">Delete</a>
    </li>

{{ else }}
    <p>There are no books.</p>

{{/books}}
</ul>

<a href="/books/add">Add Book</a>

See how we can just access the author name via {{ author.name }} in our Index.handlebars view? Mongoose makes it nice and easy to do this. Nice and easy is always good!

Editing Items and Handlebars Helpers

We will use some of the same Mongoose concepts of getting the author object reference for our edit view for books as well. What is interesting about the edit view is that we also need to find *all* the authors as well so that we can populate the dropdown. We can’t just return the current one associated with the book because maybe the user of the site would want to update the author by choosing a different author in the dropdown. So here is what this would look like in our controller…

exports.BookEdit = function(request, response){
    var id = request.params.id;
    
    Model.BookModel.findOne({ _id: id }).populate('author').exec(function(error, result){
        if(error) {
            console.log('Error');
            Validation.ErrorRedirect(response, '/books', 'There was an error finding a book in the database with this id');
        }
        else {
            if(result) {

                response.pageInfo.book = result;

                Model.AuthorModel.find({}).exec(function(error, result){

                    if(error) {
                        Validation.ErrorRedirect(response, '/books', 'There was an error getting the author list');
                    } else {
                        response.pageInfo.title = 'Edit Book';
                        response.pageInfo.authors = result
                        response.render('books/BookEdit', response.pageInfo);
                    }
                });

            } else {
                Validation.ErrorRedirect(response, '/books', 'There was an error finding a book in the database with this id');
            }
        }
    });
}

Notice how we first find our book where we look up the record in the database using the id parameter as we have been doing before. But after this we then make a call to get all authors using the Model.AuthorModel.find({}).exec() method so that we can populate the dropdown. So in our view we can make some small adjustments to display everything that we need to…

<form method="post" action="/books/edit">
    <input name="id" type="hidden" value="{{ book._id }}" />
    <label>Title</label> <input name="title" type="text" value="{{ book.title }}" />

    <select name="author" class="">
	{{#authors}}
	    <option value="{{_id}}">{{name}}</option>
	{{/authors}}
    </select>

    <label>isPublished?</label> <input name="published" type="checkbox" value="published" {{#if book.isPublished}}checked{{/if}} />
    <input type="submit" value="Submit" />
</form>

There is, however a slight problem with our edit view in its current state. You’ll notice that if we have multiple authors to choose from in our dropdown we may not have the correct author selected. By default, the first author is always selected in the dropdown (as it was in our create view). But unless the current book we are editing happens to be by the first author in the list, it will not be correct.

How do we solve this? We’ll need to have some way of adding a “selected” attribute to the correct <option> value by comparing the current book’s author _id to the _id value in the <select> dropdown. How to do this? Because our controller does not know anything about the format of the view, as it turns out, we will need to do this comparison in the view itself.

To do this we will need to create a helper method within the handlebars templating engine to select the correct value. You can find more information on how helpers work in Handlebars on the Handlebars.js website. More important for our purposes is info on how to register helpers using the express-handlebars module which can be found here on npm. Following the format of registering the helper there, we will go to our app.js file and create a Handlebars helper called “ifCond” You will see in a moment why this is going to be useful. So in our app.js file update the section where we register handlebars as the view template to the following…

/* express-handlebars - https://github.com/ericf/express-handlebars
A Handlebars view engine for Express. */
hbs = handlebars.create({
   helpers:{
       ifCond: function(v1, operator, v2, options){
           
          v1 = v1.toString(); 
          v2 = v2.toString();  
          
          switch (operator) {
            case '==':
                return (v1 == v2) ? options.fn(this) : options.inverse(this);
            case '===':
                return (v1 === v2) ? options.fn(this) : options.inverse(this);
            case '<':
                return (v1 < v2) ? options.fn(this) : options.inverse(this);
            case '<=':
                return (v1 <= v2) ? options.fn(this) : options.inverse(this);
            case '>':
                return (v1 > v2) ? options.fn(this) : options.inverse(this);
            case '>=':
                return (v1 >= v2) ? options.fn(this) : options.inverse(this);
            case '&&':
                return (v1 && v2) ? options.fn(this) : options.inverse(this);
            case '||':
                return (v1 || v2) ? options.fn(this) : options.inverse(this);
            default:
                return options.inverse(this);
           }
       }
   },
   defaultLayout: 'main'
});

app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');

What this method will do is take in 2 values and compare them as strings within our view engine. So we can now update our BookEdit view to the following…

<form method="post" action="/books/edit">
    <input name="id" type="hidden" value="{{ book._id }}" />
    <label>Title</label> <input name="title" type="text" value="{{ book.title }}" />

    <select name="author" class="tw-admin-post-author">
	{{#authors}}
	    <option value="{{_id}}"{{#ifCond _id '==' ../book.author._id}}selected{{/ifCond}}>{{name}}</option>
	{{/authors}}
    </select>

    <label>isPublished?</label> <input name="published" type="checkbox" value="published" {{#if book.isPublished}}checked{{/if}} />
    <input type="submit" value="Submit" />
</form>

Note the use of the “ifCond” inline in the option values. Because we are doing this in the {{#authors}} block, the context is the list of authors so the _id is the value of each author id within the list. However, we need to compare this to the author _id of the current book we are editing. To get the _id value of the book object we are editing we need to switch the context using the “../” syntax. Handlebars uses this to go “one context up” to the book object where we can get the author _id value of the current book. So what this “ifCond” condition is doing for each <option> is checking to see if the author _id set in value attribute in the current option is equal to the book author _id of the book we are edting. If it is, we should set the <option> value where this is a match to be selected by adding the “selected” attribute.

Now if we rerun our application and go to edit a book, we should see the correct author selected in the dropdown. Pretty neat!

Conclusion

We are really coming along in our application development. We have relational data between different data types and we’re creating the appropriate views where they are applicable. We could easily build upon this to create all kinds of different relationships and associations between data to make our application truly dynamic. All you really need to do is repeat the processes discussed above for different objects and types.

Download the files below to play around with relational data in an Express.js application. As always, don’t forget to run

$ npm install

to install the dependency modules.

Download Files
]]>
https://9bitstudios.com/2015/08/creating-an-mvc-express-js-application-part-4/feed/ 0
Creating an MVC Express.js Application (Part 3): Data Access & Validation With MongoDB https://9bitstudios.com/2015/07/creating-an-mvc-express-js-application-part-3/ https://9bitstudios.com/2015/07/creating-an-mvc-express-js-application-part-3/#respond Mon, 13 Jul 2015 12:52:34 +0000 https://9bitstudios.com/?p=1038 In previous installments we looked at getting started with creating an Express.js MVC application, creating controllers and views. And then we looked at middleware and creating a config file to store application constants.

Now we will look at something that truly makes an Express.js application dynamic (and fun): data-access… which essentially boils down to the use of a database to store, retrieve, and manipulate information.

Like many things in technology, people will always argue about what is the “best” way to do something and what the best technologies to use for doing that something are. And the way in which an application should store data is not going to be excluded from this discussion (read: Internet flame-war). It is not really part of our purposes to argue what is “best” or “better” when it comes to data-access, but it is probably worth pointing out that a lot of the Express.js and Node.js communities seem to have embraced NoSQL databases such as MongoDB, and CouchDB. There is even a full “stack” you will hear mentioned known as the MEAN stack (MongoDB, Express, AngularJS, and Node.js) — just like you’d hear of a LAMP stack (Linux, Apache, MySQL, and PHP). The inclusion of MongoDB in this shows its prominence in developer preference in Express and Node applications.

So, it is probably worth knowing a bit about how to use a MongoDB database in a Node.js and Express.js application because you are more than likely to come across it at some point in your life as a developer. So, resultantly, we’ll utilize MongoDB in our application.

Installing MongoDB

Head on over to MongoDBs home page and download MongoDB for your OS. You’ll probably just want to pick the standard install and won’t need any fancy cloud services at this point. Be sure to read through the installation section in the docs section of the site. and do the subsequent tutorials to make sure you can test out that MongoDB was installed correctly. There is a “Getting Started” section that should walk you through this where you can try out creating, reading, inserting and deleting data a sample MongoDB database.

After you have installed MongoDB create a new folder in the root of your application can call it “db”. This is where we are going to store our database and we’re going to point MongoDB to put all the files for this database in here.

To start things up, next go to the directory where you installed Mongo and navigate into the bin directory and open a command window. So on Windows, for example, if you installed in the C:\mongodb directory, you would open a command window or shell in C:\mongodb\bin. You could also get there by opening a command window anywhere and typing

cd "C:\mongodb\bin"

Then you would type the following into the command window where we should specify the path to the “db” folder we just created. So wherever your application lives on your system you’ll want to specify that path by running the following command.

mongod --dbpath "C:\path\to\application\db"

or if you’re using BASH, something like this…

mongod --dbpath /c/path/to/application/db

If all goes well, you should see a message saying that MongoDB is waiting for connections. By default at the time of this writing, the version of MongoDB being used waits for connections on port 28017… so you should see that reflected somewhere in the messaging. Leave this running by leaving this window open (you can minimize if you like).

MongoDB

NOTE: When you first run this command, MongoDB will create all the files it needs in the “db” folder we created, so you should see a number of files pop up in there. Some are quite large.

Now that we have MongoDB installed and we can connect to it, lets write some Node.js code to do some data operations! Woo hoo! Like with so many things we have done before, we will utilise a module to act as a wrapper for our data access with MongoDB. Remember, you could always set things up and write your own code in Node.js for accessing data. Using modules is basically just a way to circumvent all of that grunt work and manual labor involved in those processes. If somebody else has already done the heavy lifting in making a module, might as well make use of it.

Installing Mongoose

I am going to use a popular module for accessing MongoDB on npm called Mongoose.js (which like pretty much all Node.js modules is avialble on npm). There are probably some other modules that you could use, we’re just going to go with this one to start. So as we have done before when we are adding a new module, we need to update our package.json with a new reference to Mongoose. We will also add another module called body-parser which is going to be useful for getting data out of forms so we can save it in our database.

{
    "name": "MVC-Express-Application",
    "description": "An Express.js application using the MVC design pattern...",
    "version": "0.0.1",
    "dependencies": {
        "express": "4.4.4",
        "body-parser": "1.4.3",	
        "express-handlebars": "1.1.0",
        "morgan": "1.1.1",
        "errorhandler": "1.1.1",
        "mongoose": "3.8.8"
    }
}

Then again, we should open a shell in our project root directory and run

$ npm install

which will pull down all the Mongoose and body-parser files.

The body-parser module is middleware (which we discussed earlier), so we need to add it to our app.js file. You can add it along with the other middleware, right after the express.static statement…

app.use(express.static(path.join(__dirname, 'static')));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

Database Settings in config.js

Now, we’ll want to add some initial code to connect our running MongoDB instance. Recall earlier that we created a config.js file. This is where having a config.js file is helpful because we are extending the functionality of our application but we have a handy place to store commonly used components of it. We will need to provide Mongoose a number of different pieces of information (name, host, etc), and we can put that into our config.js file for easy access.

Recall that when we created our config.js file we added a database property to it. We wont have to provide any credentials for our MongoDB connection string when we are doing this development locally. However, if we were to move our app to production it’s very possible that we’d need to do this (e.g. if the username was “admin” and the password was “password”). So the development section of this config object might look different than the production section. We are only using the development configuration for this tutorial, but we’ll also add a database object to the production section as well only to illustrate the possibility of different configurations in different environments.

var config = {};

config.development = {

    database: {
        name: 'MVCApplication',
        host: 'localhost',
        port: '27017',
        credentials: ''
    },
    application: {
        port: 1337
    }
    
};

config.production = {

    database: {
        name: 'tradewinds',
        host: 'localhost',
        port: '8080',
        credentials: 'admin:password@' // username:password@
    },
    application: {
        port: 80
    }    
    
};

config.environment = 'development';

module.exports = config;

So we’ve got our database name, port, and host set. We can now create some data models to store in this database.

Creating Data Models

Create another folder in the root directory called “models” and in it create a new JavaScript file called “Models.js”. In this file we are going to add the following…

var config = require('../config');
var mongoose = require('mongoose');
var connectionString = 'mongodb://' + config[config.environment].database.credentials + config[config.environment].database.host + ':' + config[config.environment].database.port  + '/'+ config[config.environment].database.name;
var db = mongoose.connection;

Here we have a reference to our config file where we can use the database information we’ve set in the config file. We’ll also pull in the mongoose module. The db variable will be the object that represents our database connection. One thing that will be handy for us is having some sort of messaging to tell us if we have connected successfully to the database or if there was an error. Mongoose provides a way for us to do this through the db object…

db.on('error', function(){
    console.log('There was an error connecting to the database');
});

db.once('open', function() {
    console.log('Successfully connected to database');
});

This code will log a message to the console whether we are successful in connecting to the database or if we encounter an error.

Lastly, we’re going to want to call the code to actually connect to MongoDB through Mongoose.

mongoose.connect(connectionString);

Reading through the Mongoose.js docs you can see how to create a data model through the schema interface that mongoose provides. We’ll do something simple like create a Book model definition through the mongoose.Schema syntax and then create an actual model based off of this schema using mongoose.model. Lastly, because our Models.js file is itself a module, we’re going to want to export an object containing our models for other parts of our application (such as our Controllers) to use.

var Book = new mongoose.Schema({
    title: String,
    author: String,
    isPublished: Boolean
});

var BookModel = mongoose.model('Book', Book);

module.exports = {
    BookModel: BookModel
};

We can add as many models as we need for whatever data we want to store by repeating this approach. So if we added a “User” model (e.g. to store account information), our file would look like this…

var Book = new mongoose.Schema({
    title: String,
    author: String,
    isPublished: Boolean
});

var User = new mongoose.Schema({
    name: String,
    password: String,
    email: String
});

var BookModel = mongoose.model('Book', Book);
var UserModel = mongoose.model('User', User);

module.exports = {
    BookModel: BookModel,
    UserModel: UserModel
};

You can create whatever models you want with whatever properties you want for whatever data you need to store.

Accessing Data in Controllers and Views

So let’s now put in some code to read, write, and delete data from our controllers and views. In our “controllers” folder, create a new controller called BookController.js and add the following code…

var Model = require('../models/Models');

exports.Index = function(request, response){
};

exports.BookAdd = function(request, response){
};

exports.BookCreate = function(request, response){ 
};

We’ll add code to get and insert data into the database using our data models momentarily, but before we do that, don’t forget to update our router.js file with a reference to BookController.js and these new routes.

var HomeController = require('./controllers/HomeController');
var BookController = require('./controllers/BookController');

// Routes
module.exports = function(app){
    
    // Main Routes
    
    app.get('/', HomeController.Index);
    app.get('/other', HomeController.Other);   

    // Book Routes
    
    app.get('/books', BookController.Index);
    app.get('/books/add', BookController.BookAdd); 
    app.post('/books/add', BookController.BookCreate); 
    
};

Note that here we essentially have 2 add routes. Notice though that one is a GET route and one is a POST route. We’ll use the GET route to display the form to add a new book, and we’ll use the post route to take in the data entered into that form and add it to the database.

Now back in our BookController.js file, for our main controller in our BookController.js file (the one named Index), we’ll want to set things up so that when a user goes to the /books route, we will show all the books in the database. So do do this we’ll need add some code to fetch the books from our database and then we’ll loop over the results in our view. This is how we’ll do this in our controller…

var Model = require('../models/Models');

exports.Index = function(request, response){

    Model.BookModel.find(function(error, result){
        if (error) {
            console.log('There was an error')
        } else {
            response.pageInfo.title = 'Books';
            response.pageInfo.books = result;
            response.render('books/Index', response.pageInfo);
        }
    });

};

Basically what this code says to do is find all books. We’ll be doing the same thing we did in earlier exercises by attaching everything to the pageInfo object to send to the view. Note that the result parameter (in which will be stored a set of items that the Mongoose find query finds in our MongoDB database) will be set to a “books” property on the pageInfo object. We’ll then send the pageInfo object to the view.

Before we create the view it’s worth noting that if we have an error that occurs with a database operation (or any other operation for that matter) it’s a good idea to do a redirect with messaging to the user so he/she knows that an error occurred. So we can make use of the notifications middleware that we implemented earlier and redirect with a message in case an error occurs. So it would be good practice change the above code to..

var Model = require('../models/Models');

exports.Index = function(request, response){

    Model.BookModel.find(function(error, result){
        if (error) {
            console.log('There was an error');
            response.redirect('/?error=true&message=There was an error getting books from the database');
        } else {
            response.pageInfo.title = 'Books';
            response.pageInfo.books = result;
            response.render('books/Index', response.pageInfo);
        }
    });

};

Here we are redirecting to the home route “/” with the query string and message to display an error notifications. If we build our application right, we hope that we;ll seldom see this error. But errors do happen and it’s important that your application handles things gracefully when they do.

But if we don’t get an error in our database operation, we’ll be able to pass the data we get back to the view. Speaking of the view, let’s create that right now. In our views folder create a new folder called “books” and create an Index.handlebars file in it. Add the following code to this file…

<ul>
{{#books}}
    <li>
        <strong>{{title}}</strong> by: {{ author }} 
    </li>
{{ else }}
    <p>There are no books.</p>
{{/books}}
</ul>

<a href="/books/add">Add Book</a>

Because we passed response.pageInfo directly into the view, the “books” property is directly available to be accessed using Handlebars syntax. So the {{#books}} marker basically says loop over the “books” object that was passed to the view. The “books” object was set to the result we got back from our Mongoose query, which contains a set of book models. Thus, inside the books object both the title and author properties are available because those are part of the book model schema.

Of course, we don’t have any books in our database right now so the message stating that there are no books will appear in this case. In Handlebars, the content that follows the {{ else }} block will render if the {{ books }} set is empty.

So let’s add some code to actually add a book to the database. In our BooksController.js file, add the code to say we’re going to render a form when the user goes to the “books/add” route with a GET request (i.e. navigates there in his/her browser).

exports.Index = function(request, response){

    Model.BookModel.find(function(error, result){
        if (error) {
            console.log('There was an error');
            response.redirect('/?error=true&message=There was an error getting books from the database');
        } else {
            response.pageInfo.title = 'Books';
            response.pageInfo.books = result;
            response.render('books/Index', response.pageInfo);
        }
    });

};

exports.BookAdd = function(request, response){
    response.pageInfo.title = 'Add a Book';
    response.render('books/BookAdd', response.pageInfo);
};

exports.BookCreate = function(request, response){ 
};

All we need to do in our BookAdd GET route is set the page “title” attribute (recall that this is in our Main.handlebars layout) and then tell Express.js to render the “BookAdd” view — which we will create next. So now create a view called BookAdd.handlebars in our “views/books” directory. In this file we will add a form.

<form method="post" action="/books/add">
    <label>Title</label> <input name="title" type="text" />
    <label>Author</label> <input name="author" type="text" />
    <input type="submit" value="Submit" />
</form>

Note that this form, when submitted, will send a POST request to the BookCreate method in our controller. Even though the action is set to “/books/add”, recall in our router.js we added the line:

app.post('/books/add', BookController.BookCreate);

This means that a POST request sent to the “/books/add” endpoint will be handled by the BookCreate method in our controller. So even though the route “/books/add” is the same as the GET request, it’s the type of request that differentiates which controller method will execute.

So in our BookCreate controller we’ll need to add some code to add a new book model object to our database. So in our BookCreate method in BookController.js add the following code…

exports.BookCreate = function(request, response){ 

    var title = request.body.title;
    var author = request.body.author;

    var b = new Model.BookModel({ 
        title: title,
        author: author,
        isPublished: true
    });

    b.save(function(error){
        if(error) {
            console.log('Error');
            response.redirect('/books?error=true&message=There was an error adding the book to the database');
        } else {
            response.redirect('/books?success=true&message=Book created successfully');
        }
    });

};

Here the request object will contain the values submitted with the form on the request.body. The name attributes on each of the text fields get added to the request body. This data is then used to create a new book model object containing these values which can then be saved to the database by calling Mongoose’s save method on it. If the save is successful, we will redirect back to the home books route which will now have the book rendering as part of the list. We’ll even pass in some parameters which if you recall in an earlier discussion will be acted upon by our notification middleware to give us a “Success” message when we’ve successfully added a book! If we are for some reason unable to add a book to the database, we will redirect back to the “/books” route with an error message.

Note that we are not really doing any kind of validation of the data submitted to the form. Normally we would want to check for empty fields and/or invalid inputs. For books we can basically allow a user to enter pretty much anything (as long as there is something there) for both title and author. However, if we were, for example, storing a user’s email address on a “UserModel,” we would want to validate that the e-mail was in valid e-mail format before attempting to add the record to the database. If the e-mail provided by the user was invalid we would want to redirect back to the form with a massage informing the user that the e-mail that they had entered was invalid. You would normally do these checks for all data types and fields before you attempted to add anything to the database. This is something that we’ll revisit more in-depth later on, but it is something that is important and it’s worth mentioning here if only in passing.

Let’s update our views and controller to include the “isPublished” field. First the view…

<form method="post" action="/books/add">
    <label>Title</label> <input name="title" type="text" />
    <label>Author</label> <input name="author" type="text" />
    <label>Is Published?</label> <input name="published" type="checkbox" value="published" />
    <input type="submit" value="Submit" />
</form>

And then the controller…

exports.BookCreate = function(request, response){ 

    var title = request.body.title;
    var author = request.body.author;
    var isPublished = false;
    if(request.body.published === 'published') {
        isPublished = true;
    }

    b.save(function(error){
        if(error) {
            console.log('Error');
            response.redirect('/books?error=true&message=There was an error adding the book to the database');
        } else {
            response.redirect('/books?success=true&message=Book created successfully');
        }
    });
};

Here we have a check to see if the “isPublished” field value is coming up in the request body. If it is, it means that the box is checked. Thus we can set this value to true. If the box is not checked we will create our book in the database with the isPublished flag set to false.

Editing and Deleting Data

How would we go about doing editing and deleting items from the database? To do these actions we’ll need to have access to some sort of identifier use to have a way to tell which item (in this example which book object) we want to act upon. Fortunately MongoDB has been taking care of this for us behind the scenes. Every document in a MongoDB database has an internal “_id” property that contains a unique value that automatically gets added by MongoDB when a new item is created. More on this is discussed in the data modeling section on the MongoDB website. We could see what this key/value pair looks like if we update our view for a book to look like the following (adding an {{_id }} to the view)…

<ul>
{{#books}}
    <li>
        <strong>{{title}}</strong> by: {{ author }} - {{ _id }}
    </li>

{{ else }}
    <p>There are no books.</p>

{{/books}}
</ul>

<a href="/books/add">Add Book</a>

Now if you start up your app and go to the “/books” route, you’ll see there will now also be a code also displayed next to each item that will look something like this…

55a653333cfc15942813fa6e

and each one will be different. That collection of random letters and number is the unique _id value for this particular entry in the database. Why is this value important? Well, it’s because we’re going to make use of this value to edit and delete data. If we know the unique value of the book we want to edit or delete we can act upon it without affecting the other items in the database.

Deleting Data

So let’s actually start with deleting data and then we’ll move on to editing data. How would we do deleting? Well to start we’re going to have create a new controller method to handle delete requests. So let’s add the following method to the bottom of our BookController.js file…

exports.BookDelete = function(request, response){
    var id = request.params.id; 
    console.log('Delete: ' + id)
}

And we’re also going to want to specify the route for deleting an item in in our router.js…

...
    app.get('/books', BookController.Index);
    app.get('/books/add', BookController.BookAdd); 
    app.post('/books/add', BookController.BookCreate); 
    app.get('/books/delete/:id', BookController.BookDelete);
};

Note that we are adding a parameter for an :id. This is because we are going have to pass an id to the controller as a parameter so that the “BookDelete” controller method will know which item to delete.Recall that we discussed using these named parameters in our introduction to Express.js discussion. Please see that section if you need a quick refresher on what these are and how they work. In essence, our id value is going to be available on the request.params object. Because our parameter is named “:id” in the route, that value is made available to us there by Express.js. It is important to note again that there is nothing significant about calling our route “:id”. The name is not really important. If we had named our parameter “tacos” like so…

app.get('/books/delete/:tacos', BookController.BookDelete);

then we could access the value passed in as the first parameter by using request.params.tacos. Of course, it is always good practice to use a descriptive name that is relevant to the code you are writing (so I’d recommend against using “tacos”), but just know that you have the flexibility to name your parameters whatever you like for whatever your purposes are.

Let’s update our Index.handlebars view for books by adding a link to delete that item. We are going to make use of this unique _id key that is present on each item that we have in our database and pass it in as the parameter. So let’s update our view to look like the following…

<ul>
{{#books}}
    <li>
        <strong>{{title}}</strong> by: {{ author }} - <a href="/books/delete/{{ _id }}" onclick="return confirm('Are you sure?')">Delete</a>
    </li>
{{ else }}
    <p>There are no books.</p>

{{/books}}
</ul>

<a href="/books/add">Add Book</a>

So as can be seen here, we have the path to the delete route where we will be passing in the _id key as the parameter which we will use to go find the item we want to delete. We’re also adding a bit of confirmation in inline JavaScript to prevent users from accidentally deleting an item. Confirmation of destructive actions is always a good practice when you write software.

Now if you were to run the application, go to the books route and click on one of the Delete buttons next to a database item, you would get the confirmation message and then see the id of the item you would be trying to delete logged to the console. Of course, we have not written the code to actually delete the item from the database yet, so we’ll do that next. So, back in our “BookDelete” controller method, let’s write the code to actually delete an item. Update the code in the “BookDelete” method to look like the following…

exports.BookDelete = function(request, response){ 
    var id = request.params.id;
    Model.BookModel.remove({ _id: id }, function(error, result) {
        if(error) {
            console.log('Error');
            response.redirect('/books?error=true&message=There was an error deleting the book');
        } else {
            response.redirect('/books?success=true&message=Book deleted successfully');
        }
    });
}

The code will first get the id value from the parameter using request.params.id as we’ve been discussing, and then it will use that variable in Mongoose’s remove method.to look in the database for an item that has its “_id” value as that parameter. When it finds it, it will delete the item and then redirect to the the main “/books” route. So now if you run the app again and delete an item, if all goes well you’ll see that upon redirect the item that you deleted is no longer there. Success!

Editing Data

Editing data going to be interesting because to create an “edit” view we first have to go and get the item that we want from the database and then populate the form with its values, but we are going to use a lot of the same concepts that we use to delete an item (namely, passing an id parameter to a view).

Hopefully by now the concept of creating routes, controllers, and views is becoming somewhat familiar. So to create editing functionality we should first update our router.js file. As we did with creating an item, we’ll need to add 2 routes, one to display the item’s data in a form and the other to receive that data when the form is submitted (posted) back to the server …

...
    app.get('/books', BookController.Index);
    app.get('/books/add', BookController.BookAdd); 
    app.post('/books/add', BookController.BookCreate);
    app.get('/books/edit/:id', BookController.BookEdit);
    app.post('/books/edit', BookController.BookUpdate); 
    app.get('/books/delete/:id', BookController.BookDelete);
};

And let’s add the controller code for our route to display the form…

exports.BookEdit = function(request, response){
    var id = request.params.id;
    
    Model.BookModel.findOne({ _id: id }, function(error, result){
        if(error) {
            console.log('Error');
            response.redirect('/books?error=true&message=There was an error finding a book with this id');
        }
        else {
            response.pageInfo.title = 'Edit Book';
            response.pageInfo.book = result
            response.render('books/BookEdit', response.pageInfo);
        }
    });
}

Here again we are utilizing the _id value that gets passed forward into this view as a parameter just as we did with deleting data, only this time we are using that value to go and get (lookup) this item from the database. If we have a successful result of finding the item in the database, we’ll then pass this data to the view via the “book” property (along with the other pieces of information as we’ve been doing)

So in our view because we have appended the book property onto the pageInfo object and set it equal to all of the data in our database, the various properties of that data item will be available to us on the book object…

<form method="post" action="/books/edit">
    <input name="id" type="hidden" value="{{ book._id }}" />
    <label>Title</label> <input name="title" type="text" value="{{ book.title }}" />
    <label>Author</label> <input name="author" type="text" value="{{ book.author }}" />
    <label>isPublished?</label> <input name="published" type="checkbox" value="published" {{#if book.isPublished}}checked{{/if}} />
    <input type="submit" value="Submit" />
</form>

Note that we are using the Handlebars “if” statement syntax to check the checkbox if this database record has its “isPublished” flag set to true. Note too we’re making use of a hidden input field that stores the _id. This will be needed because when we post this form back to the server, the controller that receives the request will need to know which item to update with the new values that we set.

Speaking of which, let’s write our controller to receive this POST request…

exports.BookUpdate = function(request, response){ 

    var title = request.body.title;
    var author = request.body.author;
    var isPublished = false;
    if(request.body.published === 'published') {
        isPublished = true;
    }
    
    Model.BookModel.update(
        { _id: request.body.id }, 
        {
            title: title,
            author: author,
            isPublished: isPublished
        },
        { multi: true }, 
        function(error, result){
            if(error) {
                console.log('Error');
                response.redirect('/books?error=true&message=There was an error updating the book in the database');
            } else {
                response.redirect('/books?success=true&message=Book updated successfully');
            }        
        }
    );

}

Here we are using the “body” property that is on the request object to access the form data that contains our updated values. We call Mongoose’s update method by passing in updated values. Mongoose will update the database record we tell it to (by giving it the _id value) and will update the properties on that record with what we pass in as the second parameter.

The last thing we should do is put a handy link to edit each item in our Index.handlebars method for books using the _id value just as we did for deleting items…

<ul>
{{#books}}
    <li>
        <strong>{{title}}</strong> by: {{ author }} - <a href="/books/edit/{{ _id }}">Edit</a> <a href="/books/delete/{{ _id }}" onclick="return confirm('Are you sure?')">Delete</a>
    </li>

{{ else }}
    <p>There are no books.</p>

{{/books}}
</ul>

<a href="/books/add">Add Book</a>

Testing It All Out

Whew! That is a lot of information to digest all at once but we have written enough code to actually have a functioning system of data access with our MongoDB instance. If we still have our database running and waiting for connections on port 28017 we can open a new shell in the root of our project and run…

$ node app

You should see a message that the app has started and that we have successfully connected to the database. Now navigate to the “/books” route. Obviously we haven’t added any books yet, so there will be a message saying that there are no books. However, we can change that by going to the “/books/add” route and adding a books there. If all goes well well we should add the book and then redirect back to the “/books” route with a new shiny book in our list. From there, you can also try editing and deleting data as well.

Validation of Data

In this section we will briefly cover validation of data. We have gone over entering data into the database but we sort of glossed over the validation components i.e. verifying that the data is good before we enter it into the database.

To do validation, we are going to make use of a utilities library that we’ll call “Validation” (makes sense). Like with everything else we’ve done, we’ll make it into a module. So in the utilities folder, create a new file called Validation.js. And in the BookController.js file add a reference to this at the top.

var Validation = require('../utilities/Validation');

This is roughly what our validation file might ook like…

exports.IsNullOrEmpty = function(check){
    
    var errors = false;
    
    if(Object.prototype.toString.call(check) === '[object Array]') {
	
        for(var i=0; i < check.length; i++){
	    
            if(!check[i]) {
                errors = true;
            }
            if(check[i].trim() === '') {
                errors = true;
            }
        }
	
    }
    else if(typeof check === 'string') {
        if(!check)
            errors = true;
        if(check.trim() === '')
            errors = true;
    }
    
    return errors;
    
};

exports.Equals = function(one, two) {
    if(one === two)
        return true;
    else
        return false;
};

exports.ValidateEmail = function(email) { 
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
};

exports.ValidateDate = function(dateString) { 
    // Check pattern
    if(!/^\d{4}\/\d{1,2}\/\d{1,2}$/.test(dateString))
        return false;

    // Parse the date parts to integers
    var parts = dateString.split("/");
    var year = parseInt(parts[0], 10);
    var month = parseInt(parts[1], 10);
    var day = parseInt(parts[2], 10);

    if(year < 1000 || year > 3000 || month === 0 || month > 12)
        return false;

    var monthLength = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

    // Adjust for leap years
    if(year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0))
        monthLength[1] = 29;

    return day > 0 && day <= monthLength[month - 1];
};

Here we have a few different methods that we can pass data to and we’ll want to this before we attempt to do anything with the database. We could definitely add more methods here if we wanted to for any sort of validation that our application needed. These might include things like limiting a max number of characters, or using some regular expressions to make sure that phone numbers, credit cards or whatever else are invalid format. The important thing is that it is all here in one place where we can easily extend upon things.

So for example with our BookCreate view, we can probably just add in some validation to confirm that there are not empty strings entered into any of the fields. To do this we can use our IsNullOrEmpty method. Note that this method gives us the possibility of passing in either a single variable to check or we can pass in an array of variables to check a number of inputs at a single time,

exports.BookCreate = function(request, response){ 

    var title = request.body.title;
    var author = request.body.author;

    if(Validation.IsNullOrEmpty([title, author])) {
        response.redirect('/books/add?error=true&Please fill out all fields');
    }
 ...

Here we are doing a check if the title field and/or the author fields are empty. If either one of them are we are going to redirect to the books/add route with a message to please fill out all fields.

Speaking of redirects, we have been doing that quite a bit in our application with a lot of the same types of parameters for success and error messages in each place. Rather than write these out every time, we can roll these redirects into methods that will handle this for us. We call call these “SuccessRedirect” and “ErrorRedirect” and we can make these part of the Validation module…

exports.SuccessRedirect = function(response, route, message) {
    
    if(typeof message !== 'undefined') {
        response.redirect(route + '?success=true&message=' + message);
    }
    else {
        response.redirect(route + '?success=true');
    }
};

exports.ErrorRedirect = function(response, route, message) {
    
    if(typeof message !== 'undefined') {
	response.redirect(route + '?error=true&message=' + message);
    }
    else {
	response.redirect(route + '?error=true');
    }
};

This just gives us a way to pass in what we need without having to construct the query string every time. So our BookCreate method would become something like…

exports.BookCreate = function(request, response){ 

    var title = request.body.title;
    var author = request.body.author;

    if(Validation.IsNullOrEmpty([title, author])) {
        Validation.ErrorRedirect(response, '/books', 'Please fill out all fields');
    } else {
        var b = new Model.BookModel({ 
            title: title,
            author: author,
            isPublished: true
        });
        b.save(function(error){
            if(error) {
                console.log('Error');
                Validation.ErrorRedirect(response, '/books', 'There was an error adding the book to the database');
            } else {
                Validation.SuccessRedirect(response, '/books', 'Book created successfully');
            }
        });
    }
};

A little bit cleaner and every little bit helps. We’d also want to do the same in our controllers for editing and deleting items as well.

Going even further than this, we could also do validation against the database. For example, when adding a book we could first check to see if a book with the same name already exists in the database and redirect with an error message informing the user that they must enter a unique name — if we cared about something like that. It’s not likely that we’d want to do it with book titles because it is very possible that there could be two books with the same name written by different authors but there definitely are times when you’d want to do this sort of check. For example, with user accounts you’ll often want to
make sure that all user account names and/or e-mail addresses are unique in your system, so you’d definitely want to check if a user with the same account name/email already existed before attempting it to the database.

But since we only have a “BookModel,” let’s just hypothetically say for some reason we want all book titles to be unique in our system. This is what implementing a check against this would look like…

exports.BookCreate = function(request, response){ 

    var title = request.body.title;
    var author = request.body.author;

    if(Validation.IsNullOrEmpty([title, author])) {
        Validation.ErrorRedirect(response, '/books', 'Please fill out all fields');
    } else {

        Model.BookModel.findOne({ title: title }, function(error, result) {

            if(result) {
                Validation.ErrorRedirect(response, '/books', 'There is already a book with this title in the database');
            } else {
                var b = new Model.BookModel({ 
                    title: title,
                    author: author,
                    isPublished: true
                });


                b.save(function(error){
                    if(error) {
                        console.log('Error');
                        Validation.ErrorRedirect(response, '/books', 'There was an error adding the book to the database');
                    } else {
                        Validation.SuccessRedirect(response, '/books', 'Book created successfully');
                    }
                });
            }

        });

    }

};

As before we first check that all fields are filled out. We then look up if there is already a book with this title in the database. If it finds a result, we redirect with an error message saying, “There is already a book with this title in the database.” If not, then it is finally okay to try to add the entry to the database.

Conclusion

Wow, we have covered a lot a lot on data access so far. In upcoming installments, we will look at some more advanced concepts such as session data (signing in/out) as well as securing our application from common attacks such as cross-site request forgeries (CSRFs).

Download the files below to play around with data access. Be sure that you install MongoDB and point it at the “db” folder in the package. This folder is empty in the download, but MongoDB will automatically add all the database files when you first run the command.

Also be sure to remember to run…

$ npm install

to install all dependencies before you try to use the application.

Download Files
]]>
https://9bitstudios.com/2015/07/creating-an-mvc-express-js-application-part-3/feed/ 0
Creating an MVC Express.js Application (Part 2): Middleware and Configuration https://9bitstudios.com/2014/12/creating-an-mvc-express-js-application-part-2/ https://9bitstudios.com/2014/12/creating-an-mvc-express-js-application-part-2/#respond Fri, 19 Dec 2014 19:41:27 +0000 https://9bitstudios.com/?p=1010 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. https://localhost:1337/?success=true or https://localhost:1337/other?error=true we can see the notification appear. We can also add a message parameter as well e.g. https://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
]]>
https://9bitstudios.com/2014/12/creating-an-mvc-express-js-application-part-2/feed/ 0
Creating an MVC Express.js Application https://9bitstudios.com/2014/10/creating-an-mvc-express-js-application/ https://9bitstudios.com/2014/10/creating-an-mvc-express-js-application/#comments Sat, 18 Oct 2014 17:52:26 +0000 https://9bitstudios.com/?p=1002 Express.js is probably currently the most popular Node.js framework for building web applications and APIs. It has a good history, a good community around it, lots of modules built for it, and a fairly solid reputation.

In what follows we’re going to walk through how to build an Express.js application using the Model View Controller (MVC) design pattern. It’s likely that we’ll do this tutorial in multiple parts.We’ll start out with a simple application structure and then we’ll move on by adding more complex concepts like authentication, dynamic routing, and reading from and writing to a database.

To start, it’s a good idea to have some background on both Node.js and Express so you know some of the terminology and philosophy behind what is being discussed. If you are not entirely familiar with Express.js there is an introduction to it here. And if you’re not entirely familiar with Node.js there is a primer on Node.js here.

At the time of this writing Express is at version 4.X. If you are reading this at a later point, it’s possible that the latest version differs quite significantly from this. Be sure to check out the Express.js homepage to find information on how to properly set things up using the most current version of Express. However, it may be the case that the steps followed in this tutorial will not be fully compatible with the most recent version of Express.js

package.json

To start we’re going to want to create a package.json file. You can read more about pakcage.json here. package.json will define some metadata type things like the name and version of the application, but most importantly, it will specify what modules you will need to download and run the application. You can read more about modules in Node.js here as well as in any good introduction to Node.js. Express is itself a Node.js module and it makes use of other Node.js modules. Some modules like “http” are core Node.js modules (part of the Node.js core) and some like express.js are third-party. Core Node.js modules will always be available to your application because it is running on Node.js

So our sample package.json file will 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",		
    }
}

One item of note: the name of any given package cannot have any spaces. This is to ensure that installation of packages is easy and consistent across all environments.If people were ever wanting to install our application as a module on npm (if we ever put our application on npm) by running $ npm install MVC-Express-Application it would not work if the package was named MVC Express Application. If we ran $ npm install MVC Express Application, the CLI would get confused.

Now if we run the following from the directory where our package.json file resides

$ npm install

all of the dependencies that we have specified will be downloaded and installed into a “node_modules” directory. The great thing about this is that if we need to update the versions of our modules or add new ones, we can just add or edit this package.json file and run “npm install” again. The npm installer will figure out all of the files needed. We are limited to the modules we are installing right now, but we will be adding a lot more to this later.

Application

Next we’ll want to create an “app.js” file. This file is the kickoff/entry point of our application when it starts up. This is akin to the main() function you’d find in C++ or Java.

The first components we’re going to want to add are here…

var express = require('express');

This loads up the express module. We can now refer to it in our code.

A lot of the modules we’ll be loading up are part of the Express.js project itself. There are many useful items that our application will be utilizing at various times throughout our application. As is described in the Node.js documentation on modules, Node.js modules can be loaded via references to filenames so long as those filenames are not named the same as reserved core Node.js modules, e.g. the “http” module.

We will need to install the http and path modules (which are part of the Node.js core modules) as they will be important for our application.

var express = require('express');
var http = require('http');
var path = require('path');

We are going to want to use the Express.js set function to do certain things like set application constant values. We are going to want to set the port that our application will run through. To do this we can set our port as a constant using the set function. We can also use the “path” module in combination with the Express.js use function to set the directories from which static assets will be served. These include things such as images, CSS files, and front-end JavaScript files (such as jQuery) or anything else that our client-side views will need. So create a directory called “static” inside our main directory and update our app.js file to look like the following…

var express = require('express');
var http = require('http');
var path = require('path');
var app = express();

app.set('port', 1337);
app.use(express.static(path.join(__dirname, 'static')));

And finally, just as we had done in our Introduction to Express.js we can run our server through our set port…

var express = require('express');
var http = require('http');
var path = require('path');
var app = express();

app.set('port', 1337);
app.use(express.static(path.join(__dirname, 'static')));

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
}); 

Now if we were to run…

$ node app

We could see our app running. At this point, our app doesn’t really do much other than run the server, but we’re on our way.

Templating

To get our app to display things in the browser (the “view” part of our Model-View-Controller application), we are going to want to choose a templating engine to render variables that we process in our Express.js application out to views. There are many different templating engines out there. Jadeis a popular templating choice, but I’m going to use Express Handlebars which is based off of the Handlebars.js JavaScript templating library.

To install the express-handlebars module we are going to want to update our package.json file by adding a new item to the dependencies section…

{
    "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"
    }
}

And we are going to want to run npm install again…

$ npm install

which will pull down the express-handlebars module.

We will start out by just adding basic templating, but we will likely go back and modify this later on to be a bit more sophisticated. We’ll first want to create a “views” directory for our views. So create a new directory and call it “views” and update our code to look like the following…

var express = require('express');
var http = require('http');
var path = require('path');
var handlebars  = require('express-handlebars'), hbs;
var app = express();

app.set('port', 1337);
app.set('views', path.join(__dirname, 'views'));

/* express-handlebars - https://github.com/ericf/express-handlebars
A Handlebars view engine for Express. */
hbs = handlebars.create({
   defaultLayout: 'main'
});

app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');

app.use(express.static(path.join(__dirname, 'static')));

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

Notice how we are using app.set(‘views’, path.join(__dirname, ‘views’)); to tell our handlebars engine to look for views in this directory.

Following the documentation of the express-handlebars module, we will want to create a layout. A layout is kind of like a master view or parent view that will house all of our different views that we will load up depending on the route. We need all of the common HTML that is essential to any webpage — such as the <!DOCTYPE html> as well as and the <head> and <body> elements and anything else we might need. Adding these to each and every view definitely would not be most efficient approach and will lead to a lot of repetitive code. What if we ever have to make any changes to our main HTML structure? We would have to change each and every view file. This might not seem so bad if we only have a few views. However, if the size and complexity of our application were to grow and we had dozens or even hundreds of views, things would get out of hand pretty quickly.

Fortunately, there is a better way. With Express Handlebars we can use a “layout” which will serve as a common container for our views. Some more info on using layouts can be found here. So we need to create a directory called “layouts” inside of our views directory. After we do this, we can put a Main.handlebars file in our layouts directory that will serve as our layout…

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>MVC Express Application</title>
</head>
<body>

    {{{body}}}

</body>
</html>

We’re also going to want to create 2 different views that we’ll make use of later. Add a directory called “home” in the views directory and add 2 files…

Index.handlebars

<p>Welcome to the homepage</p>

Other.handlebars

<p>Welcome to other. This is a different route using a different view...</p>

Don’t worry too much about this syntax now. We’ll revisit the practical usage of these later.

Router

Once we put all of the items that we want into our app.js file and have our views set. We are going to want to create a router.js file. A lot of MVC application frameworks such as Laravel (PHP), ASP.NET MVC (.NET/C#) or Django (Python) have a router file, where you can set certain routes and tell the application which code to run depending the route that the user goes to. Express.js routing is discussed here here

So for example, if in our application we wanted to have a list of all books we might have a route that looks like the following…

app.get('/books', function(request, response){
    console.log('List of all books');
});

The callback function that we pass into our router will run whenever a user goes to that particular route (/books). Of course, we are going to be a lot more sophisticated with the functions we have running (we are going to call our controllers from here), but this is just a simple illustration to show how routers work.

Note the request and response arguments we are passing into our function. These two items are very important in Express,js and will contain a lot of useful information about the request sent by the client and the response that we are going to use to send data back to the client from our server.

And if we wanted to set a “details view” for each book depending on the book id our route would looks like the following…

app.get('/books/:id', function(request, response){
    console.log('Book details from book id ' + request.params.id);
});

Now if we were to go to the route “/books/4” we’d go to this route with the id 4. The id value will be available to us on the request object.

Setting up a bunch of different routes is all well and good for GET requests, but we’re going to also want to have a place for the client to send data to us — either via form submissions or AJAX requests or some other means. Fortunately, we can also easily create a POST route to receive data from the client and process it.

app.post('/books/add', function(request, response){
    console.log('Post route to handle the addition of a new book');
});

Express.js also has functions for PUT and DELETE requests.

So now that we have a basic overview of routing, let’s create a router.js file and put it in the main directory. In this file, add the following…

// Routes
module.exports = function(app){
    
    // Main Routes
    
    app.get('/', function(request, response){
    
    });

    app.get('/other', function(request, response){

    });   

};

As we can see here we have created 2 routes. One main route / and one route /other.

We also have to update our app.js and send the app object to the router. In app.js pass the app object we have been adding things to the router like so…

// send app to router
require('./router')(app);

We have seen in the router that we can send in a callback and have it be available to us whenever a user navigates to a particular route. It’s fine to do things this way, but as the number of routes we create grows, our router.js file is going to get pretty big. So to add a little bit of organization to our application, it’s probably a good idea to separate these callback functions out into separate controllers because we are using the Model View Controller (MVC) design pattern to create our application.

Controllers

Let’s call our controller “HomeController”. Create a directory called controllers and in that directory create a file called HomeController.js In HomeController, add the following…

exports.Index = function(request, response){
    response.render('home/Index');
};

exports.Other = function(request, response){
    response.render('home/Other');
};

We have added 2 controllers, one for each route in our router file. Notice the response.render function and what we are passing into it. Here we are telling express to use the views in the views/home directory and use the particular view found in there. So for the / route we are using the “Index.handlebars” view and for the /other route we are using the “Other.handlebars” view Both of these will use the Main.handlebars file as a layout, because this is what we specified in our app.js file.

So let’s update the router.js file to use our newly created controllers. Note that we need to add a reference to our controller in the.

var HomeController = require('./controllers/HomeController');

// Routes
module.exports = function(app){
    
    // Main Routes
    
    app.get('/', HomeController.Index);
    app.get('/other', HomeController.Other); 

};

Recall that we had created 2 different views earlier Index.handlebars and Other.handlebars. Now if we were to run our app with $ node app and if we navigate to localhost:1337 and localhost:1337/other we can see the different views being used for our different routes.

Passing Data to Views

Rending different views in response to different routes is a great start. However, it’s kind of bland if we are only rendering static content in each view. Let’s figure out how we can pass data to our views. Update the 2 views to the following…

Index.handlebars

<p>Welcome to the homepage of {{ title }}...</p>

Other.handlebars

<p>Welcome to {{ title }}. This is a different route using a different view...</p>

And let’s also update our HomeController.js file as well and attach the “title” property to the response object and pass that object to our view.

exports.Index = function(request, response){
    response.title = 'Hello World';
    response.render('home/Index', response);
};

exports.Other = function(request, response){
    response.title = 'Other';
    response.render('home/Other', response);
};

Notice how we are passing the dynamic data in “title” to the view by attaching it to the response object and we can see that this data is rendered out to our views using the {{ title }} syntax. We can name these properties anything we want (we could have just as easily written response.cheese), the names just have to match in our views e.g {{ cheese }}.

Now if we were to run our app and navigate to localhost:1337 and localhost:1337/other we can see the different views being used rendering our data

These properties are also available to our layouts files as well. So if we wanted to we could update our Main.handlebars file to display the title in the <title> tag found in the <head> section of our HTML document…

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{title}}</title>
</head>
<body>
 
    {{{body}}}
 
</body>
</html>

It is worth noting that it is probably not the best idea to add individual properties directly onto the response object (which could get pretty messy and unmaintainable pretty quick) so let’s pull all of our data into a single object that we’ll attach to the response. We’ll call this object “pageInfo.” So let’s update our controller to look like the following…

exports.Index = function(request, response){
    response.pageInfo = {};
    response.pageInfo.title = 'Hello World';
    response.render('home/Index', response.pageInfo);
};

exports.Other = function(request, response){
    response.pageInfo = {};
    response.pageInfo.title = 'Other';
    response.render('home/Other', response.pageInfo);
};

Fortunately, we don’t have to do anything as far as updating our views go. This is one of the nice things about separating different areas of functionality out into different places.

Obviously this is just a simple example. In a more complex application it would be here in our controllers where we might use a model object to connect to a database and get the data back from there. But that’s another tutorial for another day.

Partial Views

The express-handlebars module also supports “partial views.” What is a partial view? A partial view is merely part of a view within another view. That is, it’s a subset of HTML markup within a larger container layout. So an example of this might be a menu partial view with a list of links like “Home,” “About Us,” “Contact,” and others of the sort. This menu partial view can be referenced (included) in a larger view containing the <html> and <body> elements along with any other outer container <div> elements.

You may have seen the concept of partial views utilized in various way with other web languages. For example, you might see something like within another PHP file to include a menu. ASP.NET web forms has user cotrol .ascx files and ASP.NET MVC has it’s own implementation of partial views as well. They’re pretty common

So to do a partial with Handlebars create a folder in the views directory called “partials” and make a file called Menu.handlebars with the following in it…

 <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
    <li><a href="/contact">Contact</a></li>
</ul>

And you can include a partial view within your layout by using the {{> Menu}} syntax (with the right angle bracket). So in our Main.handlebars ;layout we can have the following…

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{title}}</title>
</head>
<body>

    {{> Menu}}
  
    {{{body}}}
  
</body>
</html>

We just need to make sure that we use the correct name of our partial view. They need to match.

Like with layouts, partial views are also able to handle data passed to them from the controller code as well, so we could really put whatever we want in them. Can’t complain about that!

Summary

We have covered a lot in this tutorial already so this is probably a good place to stop for now. We have learned how to organize a simple Express.js application into an MVC type architecture, and create a router to handle routes, controllers to process data when the user navigates to a particular route, and views to render the items we want when we pass that data to the view. In the future, we will discuss more complex components of creating an Express.js application including middleware, reading and writing data to and from a database (the model portion of MVC) and abstracting more components of an application into configuration files. Feel free to download the files below and play around with them. Don’t forget to run

$ npm install

to install the modules set in the package.json file.

Download Files
]]>
https://9bitstudios.com/2014/10/creating-an-mvc-express-js-application/feed/ 10
Express.js Authentication https://9bitstudios.com/2013/09/express-js-authentication/ https://9bitstudios.com/2013/09/express-js-authentication/#respond Mon, 30 Sep 2013 13:02:15 +0000 https://9bitstudios.com/?p=907 Now we will discuss how to implement authentication in Express.js. Express.js was discussed previously in the Introduction to Express.js. In the discussion there, we looked at how Express is a web-application framework just like CodeIgniter, Django, or Laravel except instead of running on something like Apache or Ngnix, it runs on Node.js and instead of being written in PHP or Python, it is written in JavaScript. Before looking at the following section, it might be a good idea to be familiar with Express.js by reading the introduction to Express and be familiar with Node.js as well. A Node.js Primer will help you with that.

When you think authentication in web development, you think logging in and logging out. Note that this is a little bit different from authorization, which has more to do with whether a logged in user has the permissions to do a certain action on a website. This the reason that you have different roles such as “Administrator,” “Editor,” and “User” defined within different systems. For this section we’ll focus more on authentication, but a lot of the ways that you handle authentication can also be extended upon to implement authorization.

Session-Based Authentication

When you speak of authentication in modern web applications, there are a number of different implementations you could be talking about. One of the more traditional approaches is the use of sessions. Sessions go back as far as anyone can remember with anything having to do with the web. Express.js supports sessions and you can use them just as you would in other languages like PHP.

Place the following code in a file called server.js. Obviously, in a real application we’d want to separate the markup we’re returning out into views and use a templating language to render them like we did in the introduction to Express. But for now, this will do just to serve for purpose of example…

var express = require('express');
var app = express();

app.use(express.bodyParser());
app.use(express.cookieParser('shhhh, very secret'));
app.use(express.session());


function restrict(req, res, next) {
  if (req.session.user) {
    next();
  } else {
    req.session.error = 'Access denied!';
    res.redirect('/login');
  }
}

app.get('/', function(request, response) {
   response.send('This is the homepage');
});

app.get('/login', function(request, response) {
   response.send('<form method="post" action="/login">' +
  '<p>' +
    '<label>Username:</label>' +
    '<input type="text" name="username">' +
  '</p>' +
  '<p>' +
    '<label>Password:</label>' +
    '<input type="text" name="password">' +
  '</p>' +
  '<p>' +
    '<input type="submit" value="Login">' +
  '</p>' +
  '</form>');
});

app.post('/login', function(request, response) {

    var username = request.body.username;
    var password = request.body.password;

    if(username == 'demo' && password == 'demo'){
        request.session.regenerate(function(){
        request.session.user = username;
        response.redirect('/restricted');
        });
    }
    else {
       res.redirect('login');
    }	
});

app.get('/logout', function(request, response){
    request.session.destroy(function(){
        response.redirect('/');
    });
});

app.get('/restricted', restrict, function(request, response){
  response.send('This is the restricted area! Hello ' + request.session.user + '! click <a href="/logout">here to logout</a>');
});

app.listen(8124, function(){
    console.log('Server running...');
});

Now if you run the following command in the same directory as server.js…

node server

and then open up your browser to https://localhost:8124 you can see the homepage as defined by the default route.

Now try to go to https://localhost:8124/restricted. You can see that we are redirected to the login page. Judging from the code the username and password are “demo” and “demo”. If you login with these credentials, these get sent to the POST route for “/login” in a real application you’d store these credentials in a database, use a along with a per-user salt and you’d use some sort of encryption when you stored passwords. MongoDB is a popular option for using a database, and the bcrypt library is a good option for encryption. Node.js has it’s own crypto library that you could also make use of. The crypto library supports common hashing algorithms such as md5 and sha1. If you are extra-concerned with security bcrypt is recommended because it’s slower (i.e. takes longer to crack) compared to other hashing algorithims.

So in the end, you’d really end up having a login route like look something like the one below which uses a password hash encrypted with bcrypt and stored in a MongoDB database. Assuming that when the user was created his or her password was stored in the database using bcrypt…

var bcrypt = require(bcrypt);
...
app.post('/login', function(request, response) {

    var username = request.body.username;
    var password = request.body.password;
    var salt = bcrypt.genSaltSync(10);
    var hash = bcrypt.hashSync(password, salt);
    var userObj = db.users.findOne({ username: username, password: hash });
    
    if(userObj){
        request.session.regenerate(function(){
            request.session.user = userObj.username;
            response.redirect('/restricted');
        });
    }
    else {
        res.redirect('login');
    }

});

And you may end up wanting to separate some of the authentication code out into different methods as well. Refer to the libraries above for more info on how to install and use them.

Non Session-Based Authentication

One of the great things about Express is that it contains all of the tools that you need to create a REST API right out of the box. We’ve seen the GET and POST routes used. Express.js also supports PUT and DELETE routes as well. So all that you need to define the endpoints of your REST API comes standard with your Express installation.

When you speak of creating REST APIs though, one of the main concerns of adhering to truly RESTful principles is that the server is not supposed to maintain any record of state (i.e. no sessions). Thus, we have to turn to other possible solutions for authentication (and also authorization) when it comes to security. Three common ones include Basic Authentication, OAuth, and HMAC. There are some good discussions on how to implement these various methods of authentication in other sections. These are not specific to Node.js or Express, but many of the implementations there could easily be ported over to a REST API written using Express. They follow many of the similar patterns. For example a ‘products’ endpoint in PHP (Slim Framework)…

$app->get('/products', function () use ($app) {
    ...
});

and a products endpoint (Express)…

app.get('/products', function(request, response) {
    ...
});

are very similar and you could see how you could translate one to another.

Take a look at some of the entries below for discussions on different methods of authentication for a REST API…

  • Basic HTTP Authentication with the Slim PHP Framework REST API
  • Using OAuth 2.0 for Google APIs
  • HMAC REST API Security
    • Conclusion

      Authentication can be a tricky thing to implement. There’s no one perfect catch-all solution for everything. It just depends on your needs and what type of system you are trying to implement. But hopefully some of what was discussed here points you in the right direction.

      ]]> https://9bitstudios.com/2013/09/express-js-authentication/feed/ 0 Introduction to Express.js https://9bitstudios.com/2013/09/introduction-to-express-js/ https://9bitstudios.com/2013/09/introduction-to-express-js/#respond Thu, 12 Sep 2013 15:05:01 +0000 https://9bitstudios.com/?p=901 Express is one of the more popular solutions for running a web-server and creating web applications using Node.js. If you are not familiar with Node.js and what it is all about, this primer has an introductory discussion on some of the concepts behind Node.js and some of the potential benefits it offers for certain solutions in certain environments. I highly recommend reading that first before reading what follows if you are not yet acquainted with Node.js. Express is even mentioned a bit in there as well.

      Express is a web-application framework just like Django, CodeIgniter, or Laravel. The only difference is that instead of running on something like Apache, it runs on Node.js and instead of being written in PHP or Python, it is written in JavaScript. There are other web application frameworks that run on top of Node.js (like Hapi) but Express is one of the more popular ones.

      Below is a link to what we will be building in this section…

      Demo Files

      Express, like other Node.js installations, comes in the form of a module. You can use a utility called “npm” to install it using the command line. To install Express we just have to type the following into our Node.js command line…

      $ npm install express

      This will download all of the files that Express requires (dependencies) and will place them in a folder called “node_modules”.

      Now that we have Express installed we can get started. Create a file named server.js and add the following…

      var express = require('express');
      var app = express();
      
      app.get('/', function(request, response) {
         response.send("<h1>Our Express App</h1>");
      });
      
      app.listen(8124);
      

      Then open up your favorite terminal (like BASH) and type the following…

      $ node server.js

      If you open a browser and type in https://127.0.0.1:8124/ you should see the text appear. The great thing about Express is that right out-of-the-box we can use it to define some routes and build an entire web application. If you have used Lavavel or the Slim PHP Framework or something similar this might look familiar. We can also define routes for the other HTTP verbs: POST, PUT, and DELETE. We can return HTML or we can use it to create an API that returns XML or JSON. The possibilities for what we can do with it are all there.

      Let’s try adding another route…

      var express = require('express');
      var app = express();
      
      app.get('/', function(request, response) {
         response.send("<h1>Our Express App</h1>");
      });
      
      app.get('/about', function(request, response) {
         response.send("<h1>About</h1>");
      });
      
      app.listen(8124);
      

      If you open a browser and type in https://127.0.0.1:8124/about you should see our different route rendering different markup! Pretty neat, eh?

      Of course, right now our application is not all that interesting. It’s just static markup. More importantly, we’re definitely *not* going to want to have HTML in our routes because we are violating the principle of separation of concern by mixing our view logic with our route/controller logic making a nice big plate of spaghetti. To solve this, we’re going to want to use some kind of templating engine so that we can add our markup to an HTML file but also have the file render data that we pass to it. That’s what we’ll look at next.

      Templates & Views

      Using templates to render different views in JavaScript involves passing data to a file and then using special syntax to render that data to a client — usually a browser Window of some kind. See this discussion on Templates in Backbone.js for a good introduction to JavaScript templating and templating engines. We’re going to do something similar with Express using Handlebars as our templating engine.

      To install Handlebars we’re going to want to type the following into our terminal (just as we did before when installing Express)…

      $ npm install hbs

      And now we can add it as a module…

      var express = require('express');
      var app = express();
      var hbs = require('hbs');
      
      app.get('/', function(request, response) {
         response.send("<h1>Our Express App</h1>");
      });
      
      app.get('/about', function(request, response) {
         response.send("<h1>About</h1>");
      });
      
      app.listen(8124);
      

      More info on the Handlebars module can be found here.

      We’re going to want to add a couple of additional lines and make some changes to the code that will tell Express to use HTML templates that we’ll be creating shortly. We’re going to be using HTML files — indicated by the use of the app.set(‘view engine’, ‘html’) line and notice that in our routes instead of using response.send() we’re now using response.render() to render markup using the template…

      var express = require('express');
      var app = express();
      var hbs = require('hbs');
      
      app.set('view engine', 'html');
      app.engine('html', hbs.__express);
      
      app.get('/', function(request, response) {
         response.render('index');
      });
      
      app.get('/about', function(request, response) {
         response.render('about');
      });
      
      app.listen(8124);
      

      By default, Express looks for templates in a “views” folder, so let’s add a “views” directory and create an index.html file in it with the following…

      <html>
      <head>
      <title>Express App</title>
      </head>
       
      <body>
      <h1>Our Express App with Templates</h1>
      
       
      </body>
      </html>
      

      We can also create an about.html file and place it in the same “views” folder.

      Now if we restart our server and go to the home route, we can see that Express is using this template to render the HTML to the browser. Pretty slick!

      Dynamic Templates & Passing Data to Views

      Our application is still just rendering static HTML. Let’s change that by figuring out if there is a way that we can pass data to our templates.

      Edit the index.html file in our views folder to look like the following…

      <html>
      <head>
      <title>{{title}}</title>
      </head>
       
      <body>
      <h1>{{title}}</h1>
      
       
      </body>
      </html>
      

      Now let’s edit our application…

      var express = require('express');
      var app = express();
      var hbs = require('hbs');
      
      app.set('view engine', 'html');
      app.engine('html', hbs.__express);
      
      app.get('/', function(request, response) {
         var welcome = 'Our Express App with Templates';
         response.render('index',{title:welcome});
      });
      
      app.get('/about', function(request, response) {
         response.render('about');
      });
      
      app.listen(8124);
      

      As you can see here, we are now passing data into our index.html template. The text in the title property of the object we pass in is rendered in the {{title}} section by Handlebars.

      Let’s do something a bit more complicated. Edit the server file so that it looks like the following.

      var express = require('express');
      var app = express();
      var hbs = require('hbs');
      
      app.set('view engine', 'html');
      app.engine('html', hbs.__express);
      
      app.get('/', function(request, response) {
         
         var welcome = 'Our Express App with Templates';
         
         var products = [
             {"id":1, "name":"Apple", "price": 4.99 },
             {"id":2, "name":"Pear", "price": 3.99 },
             {"id":3, "name":"Orange", "price": 5.99 }
         ];
         
         response.render('index', {title: welcome, products: products});
      });
      
      app.get('/about', function(request, response) {
         response.render('about');
      });
      
      app.listen(8124);
      

      Here in our home route we are getting an array of JSON objects that we’ve defined statically. In a real application you’d connect to some database here or get data from a web service to get the objects that you want to pass to your views.

      After this, edit the index.html view to look like the following…

      <html>
      <head>
      <title>{{title}}</title>
      </head>
       
      <body>
      <h1>{{title}}</h1>
      
      {{#each products}}
         <p>
            <a href="/product/{{id}}">{{name}} - {{ price }}</a>
         </p>
      {{/each}}
       
      </body>
      </html>
      

      Now if we go to our home route, we see more dynamic data rendered as output. Here we are using an ((#each}} loop to iterate over the list of products that we passed in.

      Let’s add a route for that. Create a /products/:id get route as follows.

      var express = require('express');
      var app = express();
      var hbs = require('hbs');
      
      app.set('view engine', 'html');
      app.engine('html', hbs.__express);
      
      app.get('/', function(request, response) {
         
         var welcome = 'Our Express App with Templates';
         
         var products = [
             {"id":1, "name":"Apple", "price": 4.99 },
             {"id":2, "name":"Pear", "price": 3.99 },
             {"id":3, "name":"Orange", "price": 5.99 }
         ];
         
         response.render('index', {title: welcome, products: products});
      });
      
      app.get('/about', function(request, response) {
         response.render('about');
      });
      
      app.get('/product/:id', function(request, response) {
          var id = request.params.id;
          response.render('product', {title: 'Product #' + id});
      });
      
      app.listen(8124);
      

      The :id part at the end indicates that it is a dynamic “id” parameter in the URL query string. As you can see, we can fetch that property out of the request by using request.params.id. Now create a product.html file and place it in our views folder…

      <html>
      <head>
      <title>{{title}}</title>
      </head>
       
      <body>
      <h1>{{title}}</h1>
       
      </body>
      </html>
      

      Here we are just rendering product #1, #2, etc. In a real application we’d do a name lookup based on the id to get all sorts of information about a specific product for this page and pass it to the view. But it gives you an idea of how you would go about rendering a dynamic page based on the id parameter.

      So that concludes our very brief introduction to Express! We have just scratched the surface and there is a lot more to explore. Next steps would include looking at things like POST, PUT, and DELETE routes, database integration, and partial templates… just to name a few. Be sure to check out ExpressJS.com for more information including the API reference and documentation.

      ]]>
      https://9bitstudios.com/2013/09/introduction-to-express-js/feed/ 0