21 min read

In this article, we will continue with the Express framework. It’s one of the most popular frameworks available and is certainly a pioneering one. Express is still widely used and several developers use it as a starting point.

(For more resources related to this topic, see here.)

Getting acquainted with Express

Express (http://expressjs.com/) is a web application framework for Node.js. It is built on top of Connect (http://www.senchalabs.org/connect/), which means that it implements middleware architecture. In the previous chapter, when exploring Node.js, we discovered the benefit of such a design decision: the framework acts as a plugin system. Thus, we can say that Express is suitable for not only simple but also complex applications because of its architecture. We may use only some of the popular types of middleware or add a lot of features and still keep the application modular.

In general, most projects in Node.js perform two functions: run a server that listens on a specific port, and process incoming requests. Express is a wrapper for these two functionalities. The following is basic code that runs the server:


var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Worldn');	
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Worldn');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

This is an example extracted from the official documentation of Node.js. As shown, we use the native module http and run a server on the port 1337. There is also a request handler function, which simply sends the Hello world string to the browser. Now, let’s implement the same thing but with the Express framework, using the following code:

var express = require('express');
var app = express();
app.get("/", function(req, res, next) {
  res.send("Hello world");
}).listen(1337);
console.log('Server running at http://127.0.0.1:1337/');

It’s pretty much the same thing. However, we don’t need to specify the response headers or add a new line at the end of the string because the framework does it for us. In addition, we have a bunch of middleware available, which will help us process the requests easily. Express is like a toolbox. We have a lot of tools to do the boring stuff, allowing us to focus on the application’s logic and content. That’s what Express is built for: saving time for the developer by providing ready-to-use functionalities.

Installing Express

There are two ways to install Express. We’ll will start with the simple one and then proceed to the more advanced technique. The simpler approach generates a template, which we may use to start writing the business logic directly. In some cases, this can save us time. From another viewpoint, if we are developing a custom application, we need to use custom settings. We can also use the boilerplate, which we get with the advanced technique; however, it may not work for us.

Using package.json

Express is like every other module. It has its own place in the packages register. If we want to use it, we need to add the framework in the package.json file. The ecosystem of Node.js is built on top of the Node Package Manager. It uses the JSON file to find out what we need and installs it in the current directory. So, the content of our package.json file looks like the following code:

{
  "name": "projectname",
  "description": "description",
  "version": "0.0.1",
  "dependencies": {
    "express": "3.x"
  }
}

These are the required fields that we have to add. To be more accurate, we have to say that the mandatory fields are name and version. However, it is always good to add descriptions to our modules, particularly if we want to publish our work in the registry, where such information is extremely important. Otherwise, the other developers will not know what our library is doing. Of course, there are a bunch of other fields, such as contributors, keywords, or development dependencies, but we will stick to limited options so that we can focus on Express.

Once we have our package.json file placed in the project’s folder, we have to call npm install in the console. By doing so, the package manager will create a node_modules folder and will store Express and its dependencies there. At the end of the command’s execution, we will see something like the following screenshot:

Node.js Blueprints

The first line shows us the installed version, and the proceeding lines are actually modules that Express depends on. Now, we are ready to use Express. If we type require(‘express’), Node.js will start looking for that library inside the local node_modules directory. Since we are not using absolute paths, this is normal behavior. If we miss running the npm install command, we will be prompted with Error: Cannot find module ‘express’.

Using a command-line tool

There is a command-line instrument called express-generator. Once we run npm install -g express-generator, we will install and use it as every other command in our terminal.

If you use the framework inseveral projects, you will notice that some things are repeated. We can even copy and paste them from one application to another, and this is perfectly fine. We may even end up with our own boiler plate and can always start from there. The command-line version of Express does the same thing. It accepts few arguments and based on them, creates a skeleton for use. This can be very handy in some cases and will definitely save some time. Let’s have a look at the available arguments:

  • -h, –help: This signifies output usage information.
  • -V, –version: This shows the version of Express.
  • -e, –ejs: This argument adds the EJS template engine support. Normally, we need a library to deal with our templates. Writing pure HTML is not very practical. The default engine is set to JADE.
  • -H, –hogan: This argument is Hogan-enabled (another template engine).
  • -c, –css: If wewant to use the CSS preprocessors, this option lets us use LESS(short forLeaner CSS) or Stylus. The default is plain CSS.
  • -f, –force: This forces Express to operate on a nonempty directory.

Let’s try to generate an Express application skeleton with LESS as a CSS preprocessor. We use the following line of command:

express --css less myapp

A new myapp folder is created with the file structure, as seen in the following screenshot:

Node.js Blueprints

We still need to install the dependencies, so cd myapp && npm install is required. We will skip the explanation of the generated directories for now and will move to the created app.js file. It starts with initializing the module dependencies, as follows:

var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

Our framework is express, and path is a native Node.js module. The middleware are favicon, logger, cookieParser, and bodyParser. The routes and users are custom-made modules, placed in local for the project folders. Similarly, as in the Model-View-Controller(MVC) pattern, these are the controllers for our application. Immediately after, an app variable is created; this represents the Express library. We use this variable to configure our application. The script continues by setting some key-value pairs. The next code snippet defines the path to our views and the default template engine:

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

The framework uses the methods set and get to define the internal properties. In fact, we may use these methods to define our own variables. If the value is a Boolean, we can replace set and get with enable and disable. For example, see the following code:

app.set('color', 'red');
app.get('color'); // red
app.enable('isAvailable');

The next code adds middleware to the framework. Wecan see the code as follows:

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(require('less-middleware')({ src: path.join(__dirname, 'public') }));
app.use(express.static(path.join(__dirname, 'public')));

The first middleware serves as the favicon of our application. The second is responsible for the output in the console. If we remove it, we will not get information about the incoming requests to our server. The following is a simple output produced by logger:

GET / 200 554ms - 170b
GET /stylesheets/style.css 200 18ms - 110b

The json and urlencoded middleware are related to the data sent along with the request. We need them because they convert the information in an easy-to-use format. There is also a middleware for the cookies. It populates the request object, so we later have access to the required data. The generated app uses LESS as a CSS preprocessor, and we need to configure it by setting the directory containing the .less files. Eventually, we define our static resources, which should be delivered by the server. These are just few lines, but we’ve configured the whole application. We may remove or replace some of the modules, and the others will continue working. The next code in the file maps two defined routes to two different handlers, as follows:

app.use('/', routes);
app.use('/users', users);

If the user tries to open a missing page, Express still processes the request by forwarding it to the error handler, as follows:

app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

The framework suggests two types of error handling:one for the development environment and another for the production server. The difference is that the second one hides the stack trace of the error, which should be visible only for the developers of the application. As we can see in the following code, we are checking the value of the env property and handling the error differently:

// development error handler
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}
// production error handler
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

At the end, the app.js file exports the created Express instance, as follows:

module.exports = app;

To run the application, we need to execute node ./bin/www. The code requires app.js and starts the server, which by default listens on port 3000.

#!/usr/bin/env node
var debug = require('debug')('my-application');
var app = require('../app');

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
  debug('Express server listening on port ' + server.address().port);
});

The process.env declaration provides an access to variables defined in the current development environment. If there is no PORT setting, Express uses 3000 as the value. The required debug module uses a similar approach to find out whether it has to show messages to the console.

Managing routes

The input of our application is the routes. The user visits our page at a specific URL and we have to map this URL to a specific logic. In the context of Express, this can be done easily, as follows:

var controller = function(req, res, next) {
  res.send("response");
}
app.get('/example/url', controller);

We even have control over the HTTP’s method, that is, we are able to catch POST, PUT, or DELETE requests. This is very handy if we want to retain the address path but apply a different logic. For example, see the following code:

var getUsers = function(req, res, next) {
  // ...
}
var createUser = function(req, res, next) {
  // ...
}
app.get('/users', getUsers);
app.post('/users', createUser);

The path is still the same, /users, but if we make a POST request to that URL, the application will try to create a new user. Otherwise, if the method is GET, it will return a list of all the registered members. There is also a method, app.all, which we can use to handle all the method types at once. We can see this method in the following code snippet:

app.all('/', serverHomePage);

There is something interesting about the routing in Express. We may pass not just one but many handlers. This means that we can create a chain of functions that correspond to one URL. For example, it we need to know if the user is logged in, there is a module for that. We can add another method that validates the current user and attaches a variable to the request object, as follows:

var isUserLogged = function(req, res, next) {
  req.userLogged = Validator.isCurrentUserLogged();
  next();
}
var getUser = function(req, res, next) {
  if(req.userLogged) {
    res.send("You are logged in. Hello!");
  } else {
    res.send("Please log in first.");
  }
}
app.get('/user', isUserLogged, getUser);

The Validator class is a class that checks the current user’s session. The idea is simple: we add another handler, which acts as an additional middleware. After performing the necessary actions, we call the next function, which passes the flow to the next handler, getUser. Because the request and response objects are the same for all the middlewares, we have access to the userLogged variable. This is what makes Express really flexible. There are a lot of great features available, but they are optional. At the end of this chapter, we will make a simple website that implements the same logic.

Handling dynamic URLs and the HTML forms

The Express framework also supports dynamic URLs. Let’s say we have a separate page for every user in our system. The address to those pages looks like the following code:

/user/45/profile

Here, 45 is the unique number of the user in our database. It’s of course normal to use one route handler for this functionality. We can’t really define different functions for every user. The problem can be solved by using the following syntax:

var getUser = function(req, res, next) {
  res.send("Show user with id = " + req.params.id);
}
app.get('/user/:id/profile', getUser);

The route is actually like a regular expression with variables inside. Later, that variable is accessible in the req.params object. We can have more than one variable. Here is a slightly more complex example:

var getUser = function(req, res, next) {
  var userId = req.params.id;
  var actionToPerform = req.params.action;
  res.send("User (" + userId + "): " + actionToPerform)
}
app.get('/user/:id/profile/:action', getUser);

If we open http://localhost:3000/user/451/profile/edit, we see User (451): edit as a response. This is how we can get a nice looking, SEO-friendly URL.

Of course, sometimes we need to pass data via the GET or POST parameters. We may have a request like http://localhost:3000/user?action=edit. To parse it easily, we need to use the native url module, which has few helper functions to parse URLs:

var getUser = function(req, res, next) {
  var url = require('url');
  var url_parts = url.parse(req.url, true);
  var query = url_parts.query;
  res.send("User: " + query.action);
}
app.get('/user', getUser);

Once the module parses the given URL, our GET parameters are stored in the .query object. The POST variables are a bit different. We need a new middleware to handle that. Thankfully, Express has one, which is as follows:

app.use(express.bodyParser());
var getUser = function(req, res, next) {
  res.send("User: " + req.body.action);
}
app.post('/user', getUser);

The express.bodyParser() middleware populates the req.body object with the POST data. Of course, we have to change the HTTP method from .get to .post or .all.

If we want to read cookies in Express, we may use the cookieParser middleware. Similar to the body parser, it should also be installed and added to the package.json file. The following example sets the middleware and demonstrates its usage:

var cookieParser = require('cookie-parser');
app.use(cookieParser('optional secret string'));
app.get('/', function(req, res, next){
    var prop = req.cookies.propName
});

Returning a response

Our server accepts requests, does some stuff, and finally, sends the response to the client’s browser. This can be HTML, JSON, XML, or binary data, among others. As we know, by default, every middleware in Express accepts two objects, request and response. The response object has methods that we can use to send an answer to the client. Every response should have a proper content type or length. Express simplifies the process by providing functions to set HTTP headers and sending content to the browser. In most cases, we will use the .send method, as follows:

res.send("simple text");

When we pass a string, the framework sets the Content-Type header to text/html. It’s great to know that if we pass an object or array, the content type is application/json. If we develop an API, the response status code is probably going to be important for us. With Express, we are able to set it like in the following code snippet:

res.send(404, 'Sorry, we cannot find that!');

It’s even possible to respond with a file from our hard disk. If we don’t use the framework, we will need to read the file, set the correct HTTP headers, and send the content. However, Express offers the .sendfile method, which wraps all these operations as follows:

res.sendfile(__dirname + "/images/photo.jpg");

Again, the content type is set automatically; this time it is based on the filename’s extension.

When building websites or applications with a user interface, we normally need to serve an HTML. Sure, we can write it manually in JavaScript, but it’s good practice to use a template engine. This means we save everything in external files and the engine reads the markup from there. It populates them with some data and, at the end, provides ready-to-show content. In Express, the whole process is summarized in one method, .render. However, to work properly, we have to instruct the framework regarding which template engine to use. We already talked about this in the beginning of this chapter. The following two lines of code, set the path to our views and the template engine:

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

Let’s say we have the following template ( /views/index.jade ):

h1= title
p Welcome to #{title}

Express provides a method to serve templates. It accepts the path to the template, the data to be applied, and a callback. To render the previous template, we should use the following code:

res.render("index", {title: "Page title here"});

The HTML produced looks as follows:

Page title here

Welcome to Page title here

If we pass a third parameter, function, we will have access to the generated HTML. However, it will not be sent as a response to the browser.

The example-logging system

We’ve seen the main features of Express. Now let’s build something real. The next few pages present a simple website where users can read only if they are logged in. Let’s start and set up the application. We are going to use Express’ command-line instrument. It should be installed using npm install -g express-generator. We create a new folder for the example, navigate to it via the terminal, and execute express –css less site. A new directory, site, will be created. If we go there and run npm install, Express will download all the required dependencies. As we saw earlier, by default, we have two routes and two controllers. To simplify the example, we will use only the first one: app.use(‘/’, routes). Let’s change the views/index.jade file content to the following HTML code:

doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    h1= title
    hr
    p That's a simple application using Express.

Now, if we run node ./bin/www and open http://127.0.0.1:3000, we will see the page. Jade uses indentation to parse our template. So, we should not mix tabs and spaces. Otherwise, we will get an error.

Next, we need to protect our content. We check whether the current user has a session created; if not, a login form is shown. It’s the perfect time to create a new middleware.

To use sessions in Express, install an additional module: express-session. We need to open our package.json file and add the following line of code:

"express-session": "~1.0.0"

Once we do that, a quick run of npm install will bring the module to our application. All we have to do is use it. The following code goes to app.js:

var session = require('express-session');
app.use(session({ secret: 'app', cookie: { maxAge: 60000 }}));
var verifyUser = function(req, res, next) {
    if(req.session.loggedIn) {
        next(); 
    } else {
        res.send("show login form");
    }   
}
app.use('/', verifyUser, routes);

Note that we changed the original app.use(‘/’, routes) line. The session middleware is initialized and added to Express. The verifyUser function is called before the page rendering. It uses the req.session object, and checks whether there is a loggedIn variable defined and if its value is true. If we run the script again, we will see that the show login form text is shown for every request. It’s like this because no code sets the session exactly the way we want it. We need a form where users can type their username and password. We will process the result of the form and if the credentials are correct, the loggedIn variable will be set to true. Let’s create a new Jade template, /views/login.jade:

doctype html
html
  head
    title= title
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    h1= title
    hr
    form(method='post')
      label Username:
      br
      input(type='text', name='username')
      br
      label Password:
      br
      input(type='password', name='password')
      br
      input(type='submit')

Instead of sending just a text with res.send(“show login form”); we should render the new template, as follows:

res.render("login", {title: "Please log in."});

We choose POST as the method for the form. So, we need to add the middleware that populates the req.body object with the user’s data, as follows:

app.use(bodyParser());

Process the submitted username and password as follows:

var verifyUser = function(req, res, next) {
  if(req.session.loggedIn) {
    next();  
  } else {
    var username = "admin", password = "admin";
    if(req.body.username === username && 
    req.body.password === password) {
      req.session.loggedIn = true;
      res.redirect('/');
    } else {
      res.render("login", {title: "Please log in."});
    }
  }  
}

The valid credentials are set to admin/admin. In a real application, we may need to access a database or get this information from another place. It’s not really a good idea to place the username and password in the code; however, for our little experiment, it is fine. The previous code checks whether the passed data matches our predefined values. If everything is correct, it sets the session, after which the user is forwarded to the home page.

Once you log in, you should be able to log out. Let’s add a link for that just after the content on the index page (views/index.jade ):

a(href='/logout') logout

Once users clicks on this link, they will be forward to a new page. We just need to create a handler for the new route, remove the session, and forward them to the index page where the login form is reflected. Here is what our logging out handler looks like:

// in app.js
var logout = function(req, res, next) {
  req.session.loggedIn = false;
  res.redirect('/');
}
app.all('/logout', logout);

Setting loggedIn to false is enough to make the session invalid. The redirect sends users to the same content page they came from. However, this time, the content is hidden and the login form pops up.

Summary

In this article, we learned about one of most widely used Node.js frameworks, Express. We discussed its fundamentals, how to set it up, and its main characteristics. The middleware architecture, which we mentioned in the previous chapter, is the base of the library and gives us the power to write complex but, at the same time, flexible applications. The example we used was a simple one. We required a valid session to provide page access. However, it illustrates the usage of the body parser middleware and the process of registering the new routes. We also updated the Jade templates and saw the results in the browser. For more information on Node.js Refer to the following URLs:

  • https://www.packtpub.com/web-development/instant-nodejs-starter-instant
  • https://www.packtpub.com/web-development/learning-nodejs-net-developers
  • https://www.packtpub.com/web-development/nodejs-essentials

Resources for Article:


Further resources on this subject:


Subscribe to the weekly Packt Hub newsletter. We'll send you the results of our AI Now Survey, featuring data and insights from across the tech landscape.

LEAVE A REPLY

Please enter your comment!
Please enter your name here