Middleware

What it is

Today I'm willing to talk about middleware. Now you guys are ready to deal with this beauty. Basically Express is a series of middleware calls.

Middleware is a function with access to the request object, the response object, and the next middleware in the application’s request-response cycle, commonly denoted by a variable named next.

- Express Documentation

What it means is that a middleware can parse, validate and modify data that comes from the requester before it reaches the route's callback. It can also redirect and end a request whenever it feels like it. it is very important that any middleware added call the next middleware, otherwise we will leave the request hanging.

Now we can understand what that Body-Parser package was doing! It was actually adding a middleware to be executed before our route, formatting the data and appending it to the request object. Interesting.

Middleware Diagram
Middleware Diagram

Serving Static Files

Now that we know what a middleware is (FINALLY!!) we can serve static files. This is how Node/Express becomes a content server. Express makes it easy to do this.

'use strict';

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

app.use(express.static('public'));

app.listen(8080, function(){
  console.log('Listening on port 8080...');
});
Making a Folder Public
                  └── nodeCode
                      ├── index.js
                      └── public
                          └── ...
                
Folder Structure

With this setup we can access every content inside the public folder by hitting: http://localhost:8080/. It is possible to create a "virtual" path prefix too, since the path does not actually exists in the file system.

'use strict';

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

app.use('static', express.static('public'));

app.listen(8080, function(){
  console.log('Listening on port 8080...');
});
Adding a Path Prefix

Doing like this we access this folder by http://localhost:8080/static/. So, if I have something like this:

                  └── nodeCode
                      ├── index.js
                      └── public
                          ├── css
                          │   └── materialDesign.css
                          ├── js
                          │   └── angular-v3.0.1.min.css
                          └── index.html
                
Public Folder Structure

We would access those files respectively:

  • http://localhost:8080/static/css/materialDesign.css
  • http://localhost:8080/static/js/angular-v3.0.1.min.css
  • http://localhost:8080/static/index.html

You can define multiple files:

'use strict';

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

app.use(express.static('public'));
app.use(express.static('files'));

app.listen(8080, function(){
  console.log('Listening on port 8080...');
});
Multiple Files Being Served

Our only concern about this multiple files serving is that the files would be looked up in the order the static folders were set.

It is possible to configure which files and folders that we want to become public, and that is a good thing.

Our First Middleware

What we know about Express's middleware:

  • Express is basically a bunch of them being executed;
  • They are executed in order of addition (A queue);
  • We can access response and request objects inside its functions;
  • A middleware MUST call the next middleware.

To keep it simple as this lecture, we are going to build a middleware that prints the time that request takes to be completed.

'use strict';

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

app.use(function(request, response, next){
  const start = new Date();
  const url = request.url;
  const method = request.method;

  response.on('finish', function(){
    const duration = +new Date() - start;
    const message = `${method} to ${url} \ntook ${duration} ms \n\n`;
    console.log(message);
  });

  next();
});

app.use(express.static('public'));

app.listen(8080, function(){
  console.log('Listening on port 8080...');
});
Time Middleware

Great! Now, for every request that reaches our server we can know how much time it took! It feels great to know Middleware! You must have a tick behind your ear asking: Ok, you said that Express is middleware behind middleware, prove it! I'm more than happy to do so.

Remember our last example at Lecture 2: Hello World With Express where we define all the routes for the Dog Service? Well, here we have it:

'use strict';

const express = require('express');
const Dog = require('./dogObjComposition');
const bodyParser = require('body-parser');
const parseUrlencoded = bodyParser.urlencoded({extend: false});
const app = express();
const dogs = [
  Dog('Brian'),
  Dog('Tina Turner'),
  Dog('Puppy 1'),
  Dog('Puppy 2'),
  Dog('Puppy 3')
];

app.route('/goodDog/:doggyId')
  .get(function (request, response) {
    const doggyId = request.params.doggyId;

    if(doggyId && doggyId < dogs.length) {
      response.send(dogs[doggyId].whoIsAGoodBoy());
    } else {
      response.sendStatus(403);
    }
  });

app.route('/wiggle/:doggyId')
  .get(function (request, response) {
    const doggyId = request.params.doggyId;

    if(doggyId && doggyId < dogs.length) {
      response.send(dogs[doggyId].wiggle());
    } else {
      response.sendStatus(403);
    }
  });

app.route('/dog')
  .post(parseUrlencoded, function (request, response) {
    const data = request.body;

    if(data){
      const newDog = Dog(data.name);

      dogs.push(newDog);

      response.status(201).send(`Dog ${data.name} added! Brian loved it.`);
    } else {
      response.sendStatus(403);
    }
  })
  .put(parseUrlencoded, function (request, response) {
    const data = request.body;

    if (data && data.index && data.name){
      const dog = dogs[data.index];
      dog.setName(data.name);

      response.send(`Dog #${data.index} had its name changed to ${dog.getName()}`);
    } else {
      response.sendStatus(403);
    }
  });

app.route('/dog/:doggyId')
  .delete(function (request, response) {
    const doggyId = request.params.doggyId;

    if (doggyId && doggyId < dogs.length) {
      const removed = dogs.splice(doggyId);

      response.send(`Dog #${doggyId} was removed. Now we have ${dogs.length} dogs.`);
    } else {
      response.sendStatus(403);
    }
  });

app.listen(8080, function () {
  console.log('Listening on port 8080...');
});
Full Dog Service Code

I will make it thinner, removing this ugly routes definitions in our bootstrap code. I can read your minds, you are all: "But how André?". Simple my friend: MIDDLEWARE! First I will create a folder to hold our routes. We have to pay attention that we have three endpoints:

  • http://localhost:8080/dog
  • http://localhost:8080/goodDog
  • http://localhost:8080/wiggle

So I will create 3 files to hold each route:

  • dogRoute.js
  • goodDogRoute.js
  • wiggleRoute.js

Before creating the routes (and to keep the code cleaner), let's move the dogs array initialization to its own file:

'use strict';

const Dog = require('./Dog');

let dogs = [
    Dog('Brian'),
    Dog('Tina Turner'),
    Dog('Puppy 1'),
    Dog('Puppy 2'),
    Dog('Puppy 3')
];

module.exports = dogs;
dogs.js (Using our object composition code)

Let's go to the dogRoute.js file:

'use strict';

const bodyParser = require('body-parser');
const parseUrlencoded = bodyParser.urlencoded({extend: false});
const express = require('express');
const router = express.Router();
const Dog = require('./Dog');
let dogs = require('./dogs');

router.route('/')
  .post(parseUrlencoded, function(request, response){
    const data = request.body;

    if(data){
      const newDog = Dog(data.name);

      dogs.push(newDog);

      response.status(201).send(`Dog ${data.name} added! Brian loved it.`);
    } else {
      response.sendStatus(403);
    }
  })
  .put(parseUrlencoded, function(request, response){
    const data = request.body;

    if (data && data.index && data.name){
      const dog = dogs[data.index];
      dog.setName(data.name);

      response.send(`Dog #${data.index} had its name changed to ${dog.getName()}`);
    } else {
      response.sendStatus(403);
    }
  });

router.route('/:doggyId')
  .delete(parseUrlencoded, function(request, response){
    const doggyId = request.params.doggyId;

    if (doggyId && doggyId < dogs.length) {
      const removed = dogs.splice(doggyId);

      response.send(`Dog #${doggyId} was removed. Now we have ${dogs.length} dogs.`);
    } else {
      response.sendStatus(403);
    }
  });

module.exports = router;
Dog Routes

It is easy to identify that I've removed the 'dog' word from the route. That is ok, I will get there. The router object will give me the ability to create routes. So I'm defining inside this router variable all the relative paths for each method that I want to map and then exporting it. wiggleRoute.js and goodDogRoute.js will have the same structure.

'use strict';

const express = require('express');
const router = express.Router();
let dogs = require('./dogs');

router.route('/:doggyId')
    .get(function(request, response) {
        var doggyIndex = request.params.doggyId;
        if(doggyIndex && doggyIndex >= 0  && doggyIndex < dogs.length) {
            response.send(dogs[doggyIndex].whoIsAGoodBoy());
        } else {
            response.sendStatus(404);
        }
    });

module.exports = router;
Good Dog Route
'use strict';

const express = require('express');
const router = express.Router();
let dogs = require('./dogs');

router.route('/:doggyId')
    .get(function(request, response) {
        const doggyIndex = request.params.doggyId;
        if(doggyIndex && doggyIndex >= 0 && doggyIndex < dogs.length) {
            response.send(dogs[doggyIndex].wiggle());
        } else {
            response.sendStatus(404);
        }
    });

module.exports = router;
Wiggle Route

Nothing on my right hand....nothing on my left hand....TA-DA!

'use strict';

const express = require('express');
const app = express();
const dogRoute = require('./dogRoute');
const goodDogRoute = require('./goodDogRoute');
const wiggleRoute = require('./wiggleRoute');

app.use('/dog', dogRoute);
app.use('/goodDog', goodDogRoute);
app.use('/wiggle', wiggleRoute);

app.listen(8080, function(){
    console.log('Listening on port 8080...');
});
Index.js Refactored

Remember when I said about relative path in the express.static middleware? We can do the same thing here, but now we are defining a common prefix for each route!

Project Scaffolding

What is Scaffolding?

We have several definitions for scaffolding, but for us scaffolding will mean:

Is the first folder structure defined for a project. It can follow any kind of standard or pattern that best fits the project's needs.

- Almeida, André

As Node.js is a runtime environment, there is no standard structure defined for it. The same goes for Express, there isn't anything pre-defined, that means that we can go nuts! Ok, not like that, but we are free to do whatever our project need.

We've seen in Lecture 1: Code Import, Using Require that Node give us the power to import any code into any file using require(). Which means that we can scatter our code all over the place and them glue them together using imports.

We've just saw that it is possible to make any folder visible to the internet using the middleware express.static(). With this we can even decouple our frontend from the backend. We still have some awesome tools, like Grunt, that allow us to modularize even more our sweet code. We even got NPM to manage our packages! So I can say that we are in a comfortable situation.

When we are facing this kind of problem, I mean, defining a folder structure, we should be asking some questions:

  • What kind of application I'm building?
  • Do we have a standard folder structure for that already?
  • How can I organize my code so I can minimize the code conflicts in merges?
  • How can I organize my code so I can work with few open folders in my sidebar?
  • Which kind of name should I give my folders so I can make it easy to find what I want?

For some of us, thinking about how we can organize our files is not that hard, because we came from a developer background which gives us the knowledge of how things can be connected and some folder patterns that we used in the past.

To prove you that I am not lying: I bet that more than half of you that are reading this knows what MVC is. Got you, didn't I? MVC is one of the most popular folder structure in a server project. The reason is that MVC have well defined rules and concepts about how a server should work and behave, so most of the developers find it warming working in a workspace that they already know. Just because we are using a bad-ass-awesome-kick-ass-new technology does not mean that we have to throw away all the cool stuff that the community already gave to us.

Bottom line? If you are building a MVC application you will create an MVC structure.

                  └── nodeCode
                      ├── Controllers
                      │   ├── userController.js
                      │   ├── friendsController.js
                      │   └── postController.js
                      ├── Model
                      │   ├── friendsDAO.js
                      │   ├── postDAO.js
                      │   └── userDAO.js
                      ├── View
                      │   ├── css/
                      │   ├── js/
                      │   ├── friendList.html
                      │   ├── index.html
                      │   └── login.html
                      ├── Routes
                      │   ├── friends.route.js
                      │   ├── index.route.js
                      │   └── login.route.js
                      └── server.js
                
MVC Folder Structure

Or you can build a structure from your head, thinking about coupling concerns

                  └── nodeCode
                      ├── Auth
                      │   └── authorization.js
                      ├── Persistent
                      │   ├── friendsDAO.js
                      │   ├── postDAO.js
                      │   └── userDAO.js
                      ├── Routes
                      │   ├── friendship
                      │   │   ├── friendshipController.js
                      │   │   └── friendshipRouting.js
                      │   ├── login
                      │   │   ├── loginController.js
                      │   │   └── loginRouting.js
                      │   └── users
                      │       ├── userController.js
                      │       └── userRouting.js
                      ├── Schema
                      │   ├── friendship.schema.js
                      │   └── user.schema.js
                      ├── config.js
                      └── index.js
                
Concerns Folder Structure

There is no right way to do it. There is the best way to solve your needs/problems. You always have to think if it is easy to understand where to find your code and if this is really organizing everything.

But we are talking about server application. We can build desktop applications too. Lets take a look into Popcorn Time folder structure:

                  └── src/app
                      ├── css
                      │   ├── animation.css
                      │   └── font-awesome.min.css
                      ├── fonts
                      │   ├── OpenSansBold.svg
                      │   ├── OpdenSans-Blod.woff
                      │   └── ...
                      ├── images
                      │   └── ...
                      ├── lib
                      │   ├── cache.js
                      │   └── ...
                      ├── styl
                      │   ├── Official_-_Black_&_Yellow_theme.styl
                      │   └── ..
                      ├── templates
                      │   ├── about.tpl
                      │   └── ...
                      ├── vendor
                      │   ├── videojshooks.js
                      │   └── videojsplugins.js
                      ├── .jshintrc
                      ├── app.js
                      ├── bootstrap.js
                      ├── common.js
                      ├── database.js
                      ├── httpapi.js
                      ├── index.html
                      ├── language.js
                      ├── settings.js
                      ├── updater.js
                      └── vpn.js
                
Popcorn Time Folder Structure

Lets use our well know patterns! Lets couple concerns! Lets decouple layers! Lets make it beautiful! Lets make it readable!

Exercises

Keep using your code which you developed on last lecture

Exercise 1:

Using the server created at Lesson 2: Exercises install the package body-parser and add two middleware to parse url encoded data and json data.

Exercise 2:

Using the same code created at Exercise 1 make the folder public available to be reached by http://localhost:3000.

Exercise 3:

Using the same code created at Exercise 2 create a config file that will hold the server configurations: host, port, appName.

Exercise 4:

CHALLENGE: Using the same code created at Exercise 3 create a middleware which will be triggered before every request. This middleware searches for a cookie in the request named as appName, where appName is a variable defined at the config file created in the last exercise, and print its contents on the console.

Exercise 5:

Using the same code created at Exercise 4 decouple your routes definitions from the index.js into another file and import it back to index.js and use it as a middleware to define your routes again.

Exercise 6:

Using the same code created at Exercise 4 move the cookie middleware into its own folder. Do the same with the file created at Exercise 5 to hold the routes. And again with userDAO and user.schema.js, put them into separate folders. Name those files the way you find it is best.

Exercise 7:

Are you IDLE? Ask me for more challenges.