Programmation serveur avec Express
Romuald THION
Semestre pair 2022 UNC
Express a des successeurs plus modernes comme https://www.fastify.io/ ou https://koajs.com/ mais reste une référence avec une très bonne documentation.
const express = require("express");
const app = express();
const port = 5000;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`);
});
En Express, comme dans la majorité des frameworks web, on va définir les étapes du traitement des requêtes et de production de réponses par des callbacks passés en paramètres.
Le patron de conception (design pattern) Modèle-Vue-Contrôleur (MVC) est un modèle d’architecture logicielle :
Dans le domaine du génie logiciel, le livre fondateurs des design patterns est le Gang Of Four. Le MVC est un pattern, qui en compose en fait plusieurs.
Mise en œuvre un peu particulière dans le cas des pages web : c’est le navigateur qui est responsable du rendu, de l’affichage
Permettent d’enchainer les traitements des requêtes HTTP via des calllbacks de la forme function(request, response, next)
.
Un middleware peut :
const promise = readFile(fileName);
response.setHeader("X-Api-Version", "2.0.1");
response.locals.user = request.user
response.json({ code: "OK" }
response.status(403).end()
Un middleware peut passer la main au prochain middleware, trois façons :
next()
: le prochain dans la liste courante de middlewaresnext("route")
: on sort de la liste courante et on continuenext(error)
: le prochain middleware d’erreur
function(error, request, response, next)
En Express, tout est middleware, voir using middlewares
app.use()
/api
ou /users
function (err, req, res, next)
express.json()
cookie-session
,express.static()
Besoin d’une fonctionnalité ?
Chercher un (bon) middleware qui l’implémente !
Middleware function requestTime
.
Ajoute un champs à l’objet Response et passe au middleware suivant via next()
. Si next()
est oublié : pas de réponse pour le client !
Attend et passe au middleware suivant via next()
.
Pour avoir un middleware configurable, il faut créer une Higher-Order Function (HOF) type décorateur
En enregistrant un middleware, on ajoute une étape à une liste de traitements. Pour chaque étape il y a :
Une requête traverse les étapes à partir du début et dans l’ordre :
next()
, next(error)
et next("route")
permettent de passer aux étapes suivantesresp.send()
permet d’envoyer la réponse attention à la suite
[ERR_HTTP_HEADERS_SENT]:
Cannot set headers after they are sent to the client`resp.send()
est async, souvent on fait return resp.send()
pour être sûr de casser le flot de traitementExemple de stack pour une application de démonstration (la liste peut avoir une vingtaine d’éléments et certains, à leur tours des dizaines de handlers) :
[
...
Layer {
handle: [Function: bound dispatch],
...
route: Route { path: '/', stack: [Array], methods: [Object] }
},
Layer {
handle: [Function: bound dispatch],
...
route: Route { path: '/:code', stack: [Array], methods: [Object] }
},
Layer {
handle: [Function (anonymous)],
...
route: undefined
}
]
Selon le cas :
throw new Error("KO");
next(erreur)
unhandledRejection
Promise.reject(new Error("async throw")).catch(next);
On va déléguer la production de HTML à un moteur de templates, qui sont des équivalents à Jinja mais dans l’écosystème JavaScript :
Express permet de choisir et configurer le moteur
Intégration des principaux moteurs template à Express
Expressjs n’intègre rien pour l’accès aux données. Il faut prendre un driver, un ORM ou un query builder
demo-knex.mjs
Extrait d’un fichier database.mjs
On donne l’exemple d’un serveur Express :
demo-base.mjs
demo-routeur.mjs
Et un exemple avec https://knexjs.org/
demo-knex.mjs
Faire la partie 2 du TP5