Express.js

J'avais bien démarré mon API, mais j'ai finalement tout recommencé. Il m'a fallu injecter un module de gestion de sessions pour permettre d'authentifier les requêtes et le plus simple pour cela était de passer par un middleware : connect ou express. Après avoir essayé les deux, j'ai finalement opté pour express qui marchait bien mieux que l'autre. Mais qu'est-ce-que ?

Node

Node.js offre une API de très bas niveau qui rebutera les développeurs PHP. C'est ce qui fait la puissance de Node : l'application est optimisée au maximum et ne s'encombre pas d'un gros serveur web complet comme Apache si ce n'est pas nécessaire. Ainsi, quand on crée un server web avec le module http, il est dans son plus simple appareil : il reçoit une requête brute et renvoie une réponse. Pas de routing, pas de $POST, pas de sessions, pas de cookies. C'est au développeur d'écrire le code dont il a besoin à partir de la requête HTTP. C'est un gros atout car on peut ainsi produire un serveur d'une légèreté optimale ne faisant que quelques lignes de codes, comparé à Apache qui gère tout mais qui nécessite aussi beaucoup plus de puissance.

Pour apporter des fonctionnalités supplémentaires à leur serveur web, certains iront coder ou récupérer quelques modules avec npm, et d'autres utiliseront un middleware.

Expressjs

Expressjs est donc un middleware. C'est un peu la colonne vertébrale de votre logiciel. Une fois l'application créée, vous allez lui faire utiliser différents modules lui permettant d'y rajouter des fonctionnalités : routage, gestion de cookie, analyse du corps de la requête, encodage d'url, service de fichier statiques, etc. Le plus simple est de regarder un exemple. Cet exemple est très classique : un serveur qui possède quelques routes dynamiques et renvoie des fichiers html générés à partir de templates et des fichiers statiques (js, css) liés.

var
express = require('express'),
routes = require('./routes'),
http = require('http'),
app = express();

app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.static(path.join(__dirname, 'public')));
app.use(app.router);
/**
* Routes
*/
app.get('/', routes.index);
app.get('/user/:id', routes.user);

app.get('*', routes.error404);

http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
});

Donc, si on y regarde en détail, que voit-on ?

Tout d'abord, nous créons une application express. À ce stade, ce n'est pas grand chose. Ensuite, nous lui configurons quelques paramètres : port, emplacement des vues, moteur de rendu. Ces paramètres seront utilisés par les modules qui vont arriver par la suite.

Nous arrivons à la méthode use() qui permet de faire utiliser des modules à l'application. C'est avec cette méthode que nous allons rajouter des vertèbres à notre colonne.

Le premier module express.favicon, se contente d'attacher un favicon à la réponse.

Le second, express.logger, permet de logguer automatiquement dans la console toutes les interactions avec l'application.

Ensuite, express.json, permet de décoder une requête encodée en json. express.urlencoded fera de même mais pour les requêtes "url encodées".

express.static est le module permettant de servir les fichiers statiques. Si la requête correspond à l'un des fichiers contenu dans le ou les dossiers passés en paramètres, alors il le renverra très rapidement et n'exécutera plus rien. Le service des fichiers statiques est ainsi extrêmement rapide.

Et pour finir, express.router, permet de gérer le routage des requêtes.

On pourrait ajouter d'autres modules. Je vous montrerais plus loin comment écrire votre propre module. Mais regardons d'abord le reste.

Express propose les quatre méthodes get(), post(), put(), delete(), correspondants aux méthodes HTTP du même nom. C'est ainsi que les routes sont créées : en passant en paramètre une route, qui peut être une expression régulière, et une fonction de callback. Cela pourra se présenter ainsi :

app.get('/', function(req, res)
{
    res.send('Hello World');
});
app.get('/kikoo', function(req, res)
{
    res.send('lol');
});

Et pour finir, nous créons un serveur http en lui passant l'app en paramètre. Et c'est ainsi que la magie opère !

Ainsi, en vous rendant sur http://localhost:3000, votre navigateur affichera "Hello World", puis en allant sur http://localhost:3000/kikoo, il vous répondra "lol".

Middleware personalisé

Le meilleur moyen de comprendre comment fonctionne un middleware est d'en faire un :

app.use(function(req, res, next)
{
    // Faites de que vous voulez ici, analysez le contenu de req,
    // modifiez le, etc

    // Nous allons pour comprendre le fonctionnement, renvoyer
    // une erreur 500 si la date est le 16 décembre
    var d = new Date();
    if (16 === d.getDate() &&
        11 === d.getMonth())
    {
        res.statusCode = 500;
        res.send('Error : we are the 16 december !');
        return;
    }

    // Si pas d'erreur, nous appelons la méthode next qui permet
    // middlewares suivants de s'éxecuter
    next();
}

Le principe est donc de placer vos briques au bon endroit dans la chaine de traitement de votre application afin d'optimiser au maximum son exécution.

Hadrien

Hi, I'm a french Javascript Lead Developer, Web Architect from Toulouse, France. I've worked for 12 years for many projects with YUI, AngularJS, Aurelia.io and now React and React native.

Toulouse, France https://hadrien.eu