Express

Express est le framework serveur web le plus utilisé pour NodeJS. Il facilite la construction d’applications structurées en microservices.

Installation

$ npm install express

Hello World

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

app.get('/foo', function (request, response) {
  response.send('Hello Foo!')
})

app.get('/bar', function (request, response) {
  response.send('Hello Bar!')
})

app.listen(3000, function () {
  console.log("Server listening on port 3000")
})

Production de la réponse

Contenu

L’appel response.send(val) envoie la réponse val dans response et ferme la connexion :

  • si val est string, le Content-Type de la réponse est mis à text/html
  • si val est object ou array, le Content-Type de la réponse est mis à application/json et val est stringifié
  • le Content-Length de la réponse est affecté
  • le status de la réponse est mis à 200
  • response est automatiquement fermée

status()

L’appel response.status(code) affecte le status de response à code et renvoie l’objet response modifié, pour chaînage. Exemple :

response.status(500).send('Erreur inconnue')

sendStatus()

res.sendStatus(200) // equivalent to res.status(200).send('OK')
res.sendStatus(403) // equivalent to res.status(403).send('Forbidden')
res.sendStatus(404) // equivalent to res.status(404).send('Not Found')
res.sendStatus(500) // equivalent to res.status(500).send('Internal Server Error')

sendFile()

res.sendFile(path)

Transfère le fichier path en assignant au header Content-Type de la requête, le mime-type associé à l’extension du fichier transféré

Headers

Ajouter un header :

res.set('Content-Type', 'application/json')
res.set('Cache-Control', 'max-age=3600, must-revalidate')
res.cookie(<name>, <value>[, <options>])

ex :

res.cookie('prefs', 'video-games,books')

Les cookies sont ensuite ajoutés à chaque requête ultérieure du navigateur.

Extraction des query params

Ils sont directement accessibles sous forme d’un dictionnaire dans request.query

const express = require('express')

const app = express()

app.get('/api/pages', function (request, response) {
  let queryParams = request.query
  console.log('queryParams', queryParams)
  //...
  response.send(...)
})

const port = process.env.PORT || 3000

app.listen(port, function () {
  console.log(`app listening on port ${port}`)
})

Test :

$ curl http://localhost:3000/api/pages?a=1&b=azer

Activité à réaliser

Recréer yesno.wtf et son webservice /api

Middlewares

Une application express est une succession ordonnée d’appels de fonctions middleware, qui transforment progressivement response à partir de request :

  • middlewares d’application
  • middlewares de routage
  • middleware de traitement d’erreurs
  • etc.

app.use(<middleware>)

Exemple :

let logger = (req, res, next) => {
  console.log('request', req)
  next()
}
app.use(logger)

app.use(<route>, <middleware>)

Exemple : app.use('/api/users', middlewareFunction)

  • capture /api/users, mais aussi /api/users/<id>, etc.
  • capture tous les verbes GET, POST, etc.

Exemple : app.use('/api/users/:id', middlewareFunction)

  • l’argument id est accessible dans request.params.id

Middleware avec paramètres

let middleware = (param1, param2) => (req, res, next) => {
   ...
}
app.use(middleware(p1, p2))

Middlewares de parsing du body

express.json() etc. ajoutent un attribut body à request contenant le contenu parsé du corps (body) de la requête, en fonction du Content-Type spécifié dans les headers

// Content-Type: application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }))

// Content-Type: application/json
app.use(express.json())

// Content-Type: html/text
app.use(express.text())

Test :

$ curl -X POST -d "azer" -H "Content-Type: text/plain" http://localhost:3000/api/pages?path=/my/page

Middleware de gestion des fichiers statiques à partir du système de fichiers du serveur

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

app.use(express.static('/var/www/html/myapp'))
app.listen(3000, () => console.log('running'))

Une requête /aaa/bbb/ccc.x conduit à servir le fichier statique /var/www/html/myapp/aaa/bbb/ccc.x

app.use('/static', express.static('/var/www/html/myapp'))

Une requête /static/aaa/bbb/ccc.x conduit à servir le fichier statique /var/www/html/myapp/aaa/bbb/ccc.x

Middleware d’ajout de headers CORS

Par défaut les API XMLHttpRequest et Fetch utilisées par les navigateurs interdisent les appels vers une destination différente de l’origine (nom de domaine ET numéro de port)

Pour les rendre possible, il faut ajouter des headers spécifiques ; c’est ce que fait le middleware ‘cors’

// allows CORS requests for all origins
app.use(cors())

Middleware de gestion des cookies

Le middleware cookie-parser extrait les cookies présents dans la requête et les met dans l’attribut req.cookies sous forme d’un dictionnaire (cookie_name, cookie_value)

app.use(cookie-parser())

Middleware de gestion des bearer tokens

const bearerToken = require('express-bearer-token')
...
app.use(bearerToken())

Le token est attaché à l’attribut .token de la requête ; il est extrait des endroits suivants :

  • dans le header Authorization: Bearer <token>
  • clé access_token dans req.body
  • clé access_token dans req.query
  • (Optional) cookie avec la clé access_token

Helmet

Ajoute des headers qui implémentent de bonnes pratiques de sécurité

app.use(helmet())

Activité à réaliser

Implémenter un point d’accès REST /api/users (sauvegardé dans un dictionnaire local)