{ Helpful Express Middleware. }

Objectives:

By the end of this chapter, you should be able to:

  • Define what middleware is
  • Write custom middleware to handle errors
  • Install and use helpful middleware including morgan
  • Create express applications faster using the express-generator

Middleware

Middleware is code that gets run in between the request and the response. We've seen some examples of middleware already; body-parser and method-override are both examples of middleware. But we can write our own middleware as well! We will also be using our own custom middleware to configure the express router and handle errors.

To include middleware we use the app.use function. Here are two examples:

// on every single request, run the following
app.use(function(req, res, next){
    console.log('Middleware just ran!')
    next()
})
// on every single request to anything that starts with /users, run the following
app.use('/users', function(req, res, next){
    console.log('Middleware just ran on a user route!')
    next()
})

Error Handling

Another tool that we can add to our applications is an easier way to manage errors (especially in production). This middleware allows errors to be built up and finally sent to an errors page. This pattern is also quite useful when you have lots of different levels of nesting and there's potential for errors to be uncaught.

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace - make sure you have a file called views/error.pug to render this error message!
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
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

You can read more about why it is so valuable to always have the next parameter and use it here and here.

morgan

Before we continue on, let's examine a useful module that will help log out requests and responses to the terminal. This module is called morgan, and can be very helpful when you're trying to debug your application.

mkdir another_express_app && cd another_express_app
touch app.js
npm init -y
npm install --save express pug body-parser morgan

Here is what our app.js might look like with all our middleware set up!

var express = require("express");
var app = express();
var morgan = require("morgan");
var bodyParser = require("body-parser");

app.set("view engine", "pug");
app.use(express.static(__dirname + "/public"));
app.use(morgan("tiny"))
app.use(bodyParser.urlencoded({extended:true}));

app.get("/", function(req, res, next){
  res.render("index");
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
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
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


app.listen(3000, function(){
  console.log("Server is listening on port 3000");
});

Generator

So far we have been generating our express applications starting with a brand new folder, installing packages and building applications from scratch. There is a faster tool for the job called express-generator, which you can install using npm install -g express-generator. We will not be making use of this module since it's valuable to learn how to create these applications from scratch, but it is a commonly used tool for generating applications quickly. You can read more about it here.

Debugging Node

One easy way to debug node application is to simply console.log values and see what the error could be. Unfortunately, this is quite time consuming so there is a better tool called locus, which you can install using npm install --save locus to pause your code at a certain line so that you can then go to the terminal and examine variables and write JavaScript. Once you have installed the module, place the line eval(require("locus")) in your application and when your code reaches that point, you can debug in the terminal.

When you're ready, move on to Express Router

Continue