Wednesday, 30 May 2018

Express.js framework

kay, coding every little detail is fun, but aren't there ways to go faster? Like frameworks for example? :-°
Good thing you asked! Coding everything by hand is OK for 5 minutes. It can be useful in certain scenarios, but most of the time it’s nice to have tools available to get it done quicker. This is why libraries and then frameworks, which are sort of super-libraries, were invented.
If you’re browsing around on NPM, you’ll soon see that there is an acclaimed module, i.e. Express.js. It’s actually a micro-framework for Node.js. It gives you basic tools to create Node.js apps faster.
But be careful: don’t go comparing Express.js with heavyweights such as Django or Symfony2! These offer you comprehensive and powerful features (such as generating administration interfaces), which is not really the case for Express.
Why? Because we’re coming from a long way behind with Node.js. Express therefore allows you to be ‘a little bit less low level’ and to generate routes (URLs) for your app more easily, for example, and to use templates. But even that’s a big step for us!
To continue with this chapter, create a file for yourself to make a test Node.js app. Install Express in it using the following command:
npm install express
You are now ready to use Express!

Routes

We have seen how tedious it was to check the requested URL with Node.js. We ended up with good old spaghetti code, like this:
if (page == '/') {
// ...
}
else if (page == '/basement') {
// ...
}
else if (page == '/floor/1/bedroom') {
// ...
}
When we create web apps, we manipulate routes as we did here. These are the different URLs to which our app must respond.
The management of routes is an important subject that has to be taken seriously. If you’ve already worked with frameworks like Django or Symfony2, you’ll know what I’m talking about. If not, just remember this: managing your website’s URLs is important, especially when it’s growing. Express helps us to do it properly.

Simple Routes

First, here’s a very basic app using Express:
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('You\'re in reception');
});
app.listen(8080);
Begin by asking for the inclusion of Express and create an app object by calling the express() function.
Then, you simply need to enter the different routes (different URLs) to which your app needs to respond. Here, I created a single route, the "/" root. A callback function is called when someone asks for this route.
This system is much better designed than our nested "if". We can write as many routes as we want like this:
app.get('/', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('You\’re in reception. How can I help you?');
});
app.get('/basement', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('You\’re in the wine cellar. Those bottles are mine!');
});
app.get('/floor/1/bedroom', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('Hey, this is a private area!');
});
If you want to manage the 404 errors, you must include the following lines at the end of your code (just before app.listen):
// ...All the route management code (app. get) is above
app.use(function(req, res, next){
res.setHeader('Content-Type', 'text/plain');
res.send(404, 'Page cannot be found!');
});
app.listen(8080);
Don’t worry too much about syntax and settings for now, we’ll come back to them in a bit. We’re just going to learn about managing routes with Express at the moment.
app.get('/', function(req, res) {
})
.get('/basement', function(req, res) {
})
.get('/floor/1/bedroom', function(req, res) {
})
.use(function(req, res, next){

Dynamic routes

Express allows you to generate dynamic routes, i.e. routes parts of which may vary. You need to write :variablenamein the URL of the route, which will create a setting that’s accessible from req.params.variablename. Like this:
app.get('/floor/:floornum/bedroom', function(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.end('You\’re in the bedroom on floor n°' + req.params.variablename);
});
This lets you create good URLs and avoids having to go via the suffix ("?variable=value") to generate variables. This way, all the following routes are valid:
  • /floor/1/bedroom
  • /floor/2/bedroom
  • /floor/3/bedroom
  • /floor/ontheroof/bedroom
Do you mean you can use anything? How can we make sure that a number is used?
The visitor can indeed enter whatever they want in the URL. So it’s up to you to check that within your callback function the setting is actually a number and to return an error (or a 404) if that’s not the case.

Templates

Up until now, we have returned HTML code directly in JavaScript. This gave us heavy and hard to handle code like this:
res.write('<!DOCTYPE html>'+
'<html>'+
' <head>'+
' <meta charset="utf-8" />'+
' <title>My Node.js page!</title>'+
' </head>'+
' <body>'+
' <p>Here is a paragraph of <strong>HTML</strong>!</p>'+
' </body>'+
'</html>');
Horrible, isn’t it? :D
Luckily, Express allows us to use templates to get out of this hell. Templates are like easy to write languages that allow us to produce HTML and insert it in the middle of variable content.
PHP is itself a template language that allows us to do this:
 <p> Are you visitor n° <?php echo $visitornum; ?></p>
There are many other template languages, like Twig, Smarty, Haml, JSP, Jade, and EJS. Express allows you to use most of these, each having their own advantages and disadvantages. In general, they manage all the essentials, i.e. variables, conditions, and loops, etc.
The principle is as follows: from your JavaScript file, you call the template of your choice by sending it the variables needed to construct the page (see next figure).
Templates with Node.js
Templates with Node.js

EJS basics

As there are many template systems around, I’m going to select just one of them. I would suggest that you use EJS (Embedded JavaScript). Install it for the project:
npm install ejs
We can now delegate the management of the (HTML) view to our template engine. No more need to write HTML code in the middle of JavaScript code like an idiot!
app.get('/floor/:floornum/bedroom', function(req, res) {
res.render('bedroom.ejs', {floor: req.params.floornum});
});
This code calls for a bedroom.ejs file that must be found in a sub-folder called "views". So create a/views/bedroom.ejsfile and put the following code in it:
<h1>You're in the bedroom </h1>
<p>You're on floor n°<%= floor %></p>
The<%= floor %>tag will be replaced by thefloorvariable that we passed on to the template with{floor: req.params.floornum}!

Multiple parameters and loops

Remember that you can send multiple settings to your templates, including arrays! For this demonstration, we’re going to create an app that counts up to a number sent as a setting and displays a random name within an array (I’m lacking inspiration, I know!).
Here’s the JavaScript code:
app.get('/count/:number', function(req, res) {
var names = ['Robert', 'Jack', 'David'];
res.render('page.ejs', {counter: req.params.number, names: names});
});
Then we transmit the number sent as a setting and a list of names in the form of an array. Then, in the EJS template:
<h1>I’m going to count to <%= counter %></h1>
<p><%
for(var i = 1 ; i <= counter ; i++) {
%>
<%= i %>...
<% } %></p>
<p>While I’m here, I’m going to take a name at random that’s been sent to me:
<%= names[Math.round(Math.random() * (names.length - 1))] %>
</p>
You can see that we can do loops with EJS templates. In fact, we use the same syntax as JavaScript (from which came the for loop).
My little tweak at the end of the code will enable me to take a random name from the array that was sent to the template.
See the result in the next figure (for/compter/66).
This app is rubbish, I know :o)
This app is rubbish, I know :o
In the same way, you can use conditions (if) and loops (while) within your EJS templates.

Taking it further

We’ve just seen two of Express’ essential features:
  • Routes: they allow efficient URL management.
  • Views: they allow access to template systems like EJS.
All of this is very useful and we could be tempted to leave it there, but that would mean ignoring the heart of Express. I suggest going further by seeing together how the heart of Express works.

Express and middleware

Express is a framework based on middleware, which are application modules each providing a specific feature. You can decide which middleware you want to load. 
Express comes with over 15 basic pieces of middleware, and of course developers can add others via NPM. Each piece of middleware provides a micro-feature. Here are a few examples:
  • compression: enables for gzip compression of pages for faster sending to the server.
  • cookie-parser: allows you to work with cookies.
  • cookie-session: allows you to generate session information (during a visitor’s stay on the website).
  • serve-static: allows the return of static files contained in a folder (images, files to download, etc.).
  • serve-favicon: manages your website's favicon.
  • csrf: provides protection against CSRF faults.
  • etc.
All these middleware offer micro-features: some of them are really small, like "serve-favicon" for example.
These pieces of middleware are interconnected and can communicate with each other. Express simply adds the routes and views above the whole thing.
All these pieces of middleware communicate with each other by sending up to 4 settings:
  • err: errors.
  • req: the visitor’s request.
  • res: a response to return (the HTML page and the header information).
  • next: a callback to the next function to be called.
If I had to summarize how these pieces of middleware work, it would look like the next figure.
The middleware communicates with the settings via Connect
The pieces of middleware communicate with each other

Using middleware in Express

To use a piece of middleware, all you need to do is call the app.use()method. You can do this, for example:
var express = require('express');
var morgan = require('morgan'); // loads the piece of middleware for logging
var favicon = require('serve-favicon'); // loads the piece of middleware for the favicon
var app = express();
app.use(morgan('combined')) // loads the piece of middleware for logging
.use(express.static(__dirname + '/public')) // Specifies that the /public folder includes static files (basic piece of middleware loaded)
.use(favicon(__dirname + '/public/favicon.ico')) // Activates the favicon specified
.use(function(req, res){ // finally answers
res.send('Hello');
});
app.listen(8080);
As you can see, I’ve used the "morgan", "static" (alias for serve-static), and "favicon" middleware here. Each piece of middleware will return the data to itself (the request, the response, the next function to be called, etc.). Each has a specific role. To know how to use them, you simply need to read the documentation.
I could stretch this out and present the middleware one by one, but it would be long and tedious (for me as well as for you). So I don’t want to go into detail, but I think that you have the essential information, which was the most complicated to understand. ;)
In a nutshell: Express offers a range of middleware that interact together. Call these pieces of middleware to use their features and be careful which order you call them as it is important (e.g. you don’t want to activate a logger at the end of the operations!).
You are ready to confront the terrible and fascinating world of Express, an essential framework that is evolving rapidly. Well done and enjoy reading the documentation now! :)

Summing up

  • Express.js is a micro-framework for Node.js. The most common tasks are therefore greatly simplified.
  • Express specifically allows the simple management of routes (the different URLs accepted by your app).
  • Express provides a bridge between template engines (such as EJS). These allow us to separate occupational code (backend) from HTML code (frontend). This spells the end for lengthywrite()  calls.
  • Express is based on middleware, which are mini-layer applications that offer features such as sessions, gzip page compression, cookie handling, etc.


No comments:

Post a Comment