Mis à jour le mardi 2 janvier 2018
  • 10 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

Vous pouvez être accompagné et mentoré par un professeur particulier par visioconférence sur ce cours.

J'ai tout compris !

Le framework Express.js

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Bon, coder à bas niveau tous les détails c'est amusant, mais est-ce qu'il n'existe pas des moyens d'aller un peu plus vite par hasard ? Des frameworks par exemple ? :-°

Vous avez bien raison. Tout coder à la main ça va 5 minutes. Ca peut être utile dans certains cas précis d'ailleurs, mais dans la plupart des cas on aime avoir des outils à disposition pour aller plus vite. C'est pour cela qu'on a inventé les bibliothèques, puis les frameworks qui sont des sortes de super-bibliothèques.

Si vous flânez un peu sur NPM, vous allez vite voir qu'il existe un module plébiscité : Express.js. Il s'agit en fait d'un micro-framework pour Node.js. Il vous fournit des outils de base pour aller plus vite dans la création d'applications Node.js.

Mais attention : n'allez pas comparer Express.js avec des poids lourds comme Django ou Symfony2 ! Ceux-ci vous offrent des fonctionnalités très complètes et puissantes (comme la génération d'interfaces d'administration), ce qui n'est pas vraiment le cas d'Express.
Pourquoi ? Parce qu'on part de loin avec Node.js. Express vous permet donc d'être "un peu moins bas niveau" et de gérer par exemple plus facilement les routes (URL) de votre application et d'utiliser des templates. Rien que ça, ça va déjà être une petite révolution pour nous !

Pour suivre ce chapitre, créez-vous un dossier pour faire une application de test Node.js. Installez-y Express avec la commande :

npm install express

Vous voilà prêts à utiliser Express !

Les routes

Nous avons vu à quel point il était fastidieux de vérifier l'URL demandée avec Node.js. On aboutissait à du bon vieux code spaghetti du type :

if (page == '/') {
    // ...
}
else if (page == '/sous-sol') {
    // ...
}
else if (page == '/etage/1/chambre') {
    // ...
}

Lorsqu'on crée des applications web, on manipule des routes comme ici. Ce sont les différentes URL auxquelles notre application doit répondre.

La gestion des routes un sujet important qui doit être traité avec sérieux. Si vous avez déjà manipulé des frameworks comme Django ou Symfony2, vous voyez certainement ce que je veux dire. Sinon, retenez juste ceci : bien gérer les URL de son site est important, surtout lorsque celui-ci grossit. Express nous aide à faire ça bien.

Routes simples

Voici une application très basique utilisant Express pour commencer :

var express = require('express');

var app = express();

app.get('/', function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Vous êtes à l\'accueil');
});

app.listen(8080);

Vous commencez par demander l'inclusion d'Express et vous créez un objet app en appelant la fonction express().

Ensuite, il vous suffit d'indiquer les différentes routes (les différentes URL) à laquelle votre application doit répondre. Ici, j'ai créé une seule route, la racine "/". Une fonction de callback est appelée quand quelqu'un demande cette route.

Ce système est beaucoup mieux fait que nos "if" imbriqués. On peut écrire autant de routes de cette façon qu'on le souhaite :

app.get('/', function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Vous êtes à l\'accueil, que puis-je pour vous ?');
});

app.get('/sous-sol', function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Vous êtes dans la cave à vins, ces bouteilles sont à moi !');
});

app.get('/etage/1/chambre', function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hé ho, c\'est privé ici !');
});

Si vous voulez gérer les erreurs 404, vous devez inclure les lignes suivantes à la fin de votre code obligatoirement (juste avant app.listen) :

// ... Tout le code de gestion des routes (app.get) se trouve au-dessus

app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');
    res.send(404, 'Page introuvable !');
});

app.listen(8080);

Ne vous préoccupez pas trop pour l'instant de la syntaxe et des paramètres, on y reviendra un peu plus tard. Nous apprenons juste à gérer les routes avec Express pour le moment.

Routes dynamiques

Express vous permet de gérer des routes dynamiques, c'est-à-dire des routes dont certaines portions peuvent varier. Vous devez écrire:nomvariabledans l'URL de la route, ce qui aura pour effet de créer un paramètre accessible depuisreq.params.nomvariable. Démonstration :

app.get('/etage/:etagenum/chambre', function(req, res) {
    res.setHeader('Content-Type', 'text/plain');
    res.end('Vous êtes à la chambre de l\'étage n°' + req.params.etagenum);
});

Cela vous permet de créer de belles URL et vous évite d'avoir à passer par le suffixe ("?variable=valeur") pour gérer des variables. Ainsi, toutes les routes suivantes sont valides :

  • /etage/1/chambre

  • /etage/2/chambre

  • /etage/3/chambre

  • /etage/nawak/chambre

Comment ça, on peut mettre n'importe quoi ? Comment fait-on pour imposer la présence d'un nombre ?

Oui, le visiteur peut écrire n'importe quoi dans l'URL (même "nawak" ;) ). C'est donc à vous de vérifier dans votre fonction de callback que le paramètre est bien un nombre et de renvoyer une erreur (ou une 404) si ce n'est pas le cas.

Les templates

Jusqu'ici, nous avions renvoyé le code HTML directement en JavaScript. Cela nous avait donné du code lourd et délicat à maintenir qui ressemblait à ça :

res.write('<!DOCTYPE html>'+
'<html>'+
'    <head>'+
'        <meta charset="utf-8" />'+
'        <title>Ma page Node.js !</title>'+
'    </head>'+ 
'    <body>'+
'     	<p>Voici un paragraphe <strong>HTML</strong> !</p>'+
'    </body>'+
'</html>');

Horrible, n'est-ce pas ? :D

Express nous permet d'utiliser des templates pour sortir de cet enfer. Les templates sont en quelque sorte des langages faciles à écrire qui nous permettent de produire du HTML et d'insérer au milieu du contenu variable.

PHP lui-même est en fait un langage de template qui nous permet de faire ceci :

 <p> Êtes vous le visiteur n° <?php echo $visiteurnum; ?></p>

Il existe beaucoup d'autres langages de templates, comme Twig, Smarty, Haml, JSP, Jade, EJS... Express vous permet d'utiliser la plupart d'entre eux, chacun ayant son lot d'avantages et d'inconvénients. En général ils gèrent tous l'essentiel, à savoir : les variables, les conditions, les boucles, etc.

Le principe est le suivant : depuis votre fichier JavaScript, vous appelez le template de votre choix en lui transmettant les variables dont il a besoin pour construire la page.

Les templates avec Node.js
Les templates avec Node.js

Les bases d'EJS

Comme il existe de nombreux systèmes de templates, je vais en choisir un dans le lot. Je vous propose ici d'utiliser EJS (Embedded JavaScript). Installez-le pour le projet :

npm install ejs

Nous pouvons maintenant déléguer la gestion de la vue (du HTML) à notre moteur de template. Plus besoin d'écrire du HTML au milieu du code JavaScript comme un cochon !

app.get('/etage/:etagenum/chambre', function(req, res) {
    res.render('chambre.ejs', {etage: req.params.etagenum});
});

Ce code fait appel à un fichier chambre.ejs qui doit se trouver dans un sous-dossier appelé "views". Créez donc un fichier/views/chambre.ejset placez-y le code suivant :

<h1>Vous êtes dans la chambre</h1>

<p>Vous êtes à l'étage n°<%= etage %></p>

La balise<%= etage %>sera remplacée par la variableetageque l'on a transmise au template avec{etage: req.params.etagenum}!

Plusieurs paramètres et des boucles

Sachez que vous pouvez envoyer plusieurs paramètres à vos templates, y compris des tableaux ! Pour cette démonstration, nous allons faire une application qui compte jusqu'à un nombre envoyé en paramètre et qui affiche un nom au hasard au sein d'un tableau (je suis en manque d'inspiration, je sais).

Voici le code JavaScript :

app.get('/compter/:nombre', function(req, res) {
    var noms = ['Robert', 'Jacques', 'David'];
    res.render('page.ejs', {compteur: req.params.nombre, noms: noms});
});

On transmet le nombre envoyé en paramètre et une liste de noms sous forme de tableau. Ensuite, dans le template EJS :

<h1>Je vais compter jusqu'à <%= compteur %></h1>

<p><%
    for(var i = 1 ; i <= compteur ; i++) {
    %>

    <%= i %>... 

<% } %></p>

<p>Tant que j'y suis, je prends un nom au hasard qu'on m'a envoyé :
<%= noms[Math.round(Math.random() * (noms.length - 1))] %>
</p>

Vous voyez qu'on peut faire des boucles avec les templates EJS. En fait, on utilise la même syntaxe que JavaScript (d'où la boucle for).
Ma petite manipulation à la fin du code me permet de prendre un nom au hasard dans le tableau qui a été envoyé au template.

Résultat (pour/compter/66) :

Cette application est inutile, je sais :o)
Cette application est inutile, je sais :o)

De la même façon, vous pouvez avoir recours à des conditions (if) et des boucles (while) au sein de vos templates EJS.

Aller plus loin : les middlewares

Nous venons de voir deux fonctionnalités essentielles d'Express :

  • Les routes : elles permettent de gérer efficacement les URL

  • Les vues : elles permettent un accès aux systèmes de templates comme EJS

Tout ceci est déjà très utile et on pourrait être tenté de s'arrêter là... mais ce serait passer à côté du coeur d'Express. Je vous propose d'aller plus loin en découvrant ensemble comment fonctionne Express dans ses entrailles. :pirate:

Express et les middlewares

Express est un framework basé sur le concept de middlewares. Ce sont des petits morceaux d'application qui rendent chacun un service spécifique. Vous pouvez charger uniquement les middlewares dont vous avez besoin.

Express est fourni avec une quinzaine de middlewares de base, et d'autres développeurs peuvent bien entendu en proposer d'autres via NPM. Les middlewares livrés avec Express fournissent chacun des micro-fonctionnalités. Il y a par exemple :

  • compression : permet la compression gzip de la page pour un envoi plus rapide au navigateur

  • cookie-parser : permet de manipuler les cookies

  • cookie-session : permet de gérer des informations de session (durant la visite d'un visiteur)

  • serve-static : permet de renvoyer des fichiers statiques contenus dans un dossier (images, fichiers à télécharger...)

  • serve-favicon : permet de renvoyer la favicon du site

  • csrf : fournit une protection contre les failles CSRF

  • etc.

Tous ces middlewares offrent vraiment des micro-fonctionnalités. Il y en a des tous petits comme "serve-favicon" par exemple.

Ces middlewares sont interconnectés et peuvent communiquer entre eux. Express ne fait qu'ajouter les routes et les vues par-dessus l'ensemble.

Tous ces middlewares communiquent entre eux en se renvoyant jusqu'à 4 paramètres :

  • err: les erreurs

  • req: la requête du visiteur

  • res: la réponse à renvoyer (la page HTML et les informations d'en-tête)

  • next: un callback vers la prochaine fonction à appeler

Si je devais résumer comment communiquent les middlewares dans un schéma, ça donnerait ça :

Les middlewares communiquent les paramètres grâce à Connect
Les middlewares communiquent entre eux

Utiliser les middlewares au sein d'Express

Concrètement, il suffit d'appeler la méthodeapp.use() pour utiliser un middleware. Vous pouvez les chaîner (les appeler les uns à la suite des autres). Par exemple, vous pouvez faire :

var express = require('express');
var morgan = require('morgan'); // Charge le middleware de logging
var favicon = require('serve-favicon'); // Charge le middleware de favicon

var app = express();

app.use(morgan('combined')) // Active le middleware de logging
.use(express.static(__dirname + '/public')) // Indique que le dossier /public contient des fichiers statiques (middleware chargé de base)
.use(favicon(__dirname + '/public/favicon.ico')) // Active la favicon indiquée
.use(function(req, res){ // Répond enfin
    res.send('Hello');
});

app.listen(8080);

Comme vous le voyez, j'ai fait appel aux middlewares morgan, static (alias de serve-static) et favicon dans le cas présent. Chaque middleware va se renvoyer des données (la requête, la réponse, la fonction suivante à appeler...). Chacun a un rôle très précis. Pour savoir les utiliser il suffit de lire la doc.

Je pourrais m'étendre et présenter les middlewares un à un, mais ce serait long et fastidieux (pour moi, comme pour vous). Je ne souhaite pas rentrer plus dans le détail mais j'estime que vous savez l'essentiel, qui était le plus compliqué à comprendre. ;)

Je résume : Express propose un ensemble de middlewares qui communiquent entre eux. Appelez ces middlewares pour utiliser leurs fonctionnalités et faites attention à l'ordre d'appel qui est important (on n'active pas un logger à la fin des opérations !).

Vous êtes prêts à affronter le monde terrible et passionnant d'Express, un framework incontournable qui évolue rapidement. Bravo et bonne lecture de la doc maintenant ! :)

Exemple de certificat de réussite
Exemple de certificat de réussite