I Introduction aux modules Express et Ejs

I.1 Présentation

Le module Express permet de gérer facilement :

  • le routing ;
  • les sessions ;
  • l’interfaçage avec un générateur de template (compatible, ici Ejs sera utilisé).

Les documentations sont accessibles aux liens suivants :

I.2 Installation d’Express et d’Ejs

npm install express -save
npm install ejs -save

I.3 Hello Word

Premier exemple permettant de comprendre la structure de base

const express = require('express')  

const app = express()
const port = 8080

app.get('/', (req, res) => {
  res.send('Hello world!')
})

app.listen(port, () => {
  console.log(`Ecoute sur http://localhost:${port} avec Express`)
})

L’objet app va gérer toutes les connexions entrantes. Ici il écoute sur le port 8080 et renverra :

  • une réponse pour tout accès de type GET sur l’url path « / »
    • ici « Hello world! »
  • une réponse de non existance d’URL path si non définie

Exemple de retour pour une URL non gérée: de type « http://127.0.0.1/test »

Cannot GET /test

I.4 Hello Word avec template Ejs

Les templates sont stockés par défaut dans un sous répertoire nommé « views ». Le fichier « acceuil.ejs » est créé et il contiendra la code suivant :

<!DOCTYPE html>
<html>
	<head>
		<title>Hello</title>
	</head>
	<body>

		<h1>Acceuil</h1>
		<p> Hello World </p>
	</body>
</html>

On revient dans le fichier à la racine qui sera lancé dans node.js :

const express 	= require('express')
const ejs	= require('ejs'); 

// Instancie l'application express
const app = express()
// associe le moteur de template Ejs à Express
app.set('view engine', 'ejs');

const port = 8080

app.get('/', (req, res) => {
  
	// récupère le template accueil.ejs et envoie le flux http au client
	res.render('accueil');	

})

app.listen(port, () => {
  console.log(`Ecoute sur http://localhost:${port} avec Express`)
})

Ici l’exemple est plutôt trivial mais c’est le principe général. On remarque :

  • pas besoin de déclarer le nom complet du template (accueil.ejs),
  • pas besoin de fermer la connexion (res.end()). La méthode « .render() » s’en occupe

Deuxième exemple avec un template utilisant un paramètre qui contiendra « Hello Word ».

Contenu du fichier « accueil.js » :

<!DOCTYPE html>
<html>
	<head>
		<title>Hello</title>
	</head>
	<body>
		<h1>Acceuil</h1>
		<p> <%= texte %> </p>
	</body>
</html>

Ici le code javascript est iclus dans les balise <% …%>. Et dans ce cas précis les balises <%= … %> affiche le contenu de la variable.

On revient dans le fichier à la racine qui sera lancé dans node.js :

const express 	= require('express')
const ejs		= require('ejs'); 

// Instancie l'application express
const app = express()
// associe le moteur de template Ejs à Express
app.set('view engine', 'ejs');

const port = 8080

app.get('/', (req, res) => {
  
  	let texte = "Hello World ! (paramètre vers le template)"
	// récupère le template accueil.ejs et envoie le flux http au client
	res.render('accueil', {texte:texte});	

})

app.listen(port, () => {
  console.log(`Ecoute sur http://localhost:${port} avec Express`)
})

On remarque que :

  • la variable texte contient bien « Hello world …’
  • que cette variable est transmise au template via cette ligne javascript : res.render(‘accueil’, {texte:texte});

II Module Express

Il est composé de 5 principaux composants :

  • Express : fonction la plus haut niveau.
    • Retourne un objet de type « Application » pour une simple instiation
    • Voir en détails en utilisant les méthodes spécifiques (peut retourner un objet routeur par ex)
  • Application : c’est l’objet principal. Suivant les méthodes utilisées, et plus particulièrement les callback, les objets « Request » et « Response » sont utilisés
  • Request : objet dédié à la demande
  • Response : objet dédié à la réponse
  • Router : utilisé pour des middlewares personnels dans le cadre du routing.

Les objets les plus utilisés seront : Application; Request et Responses

II.1 Application

C’est cet objet qui permettra de faire essentiellement du routing. il faut retenir les méthodes suivantes :

app.all()Va traiter tous les types de requêtes HTTP (PUT, GET, DELETE,POST) ou autres.
Cette méthode est pratique pour mettre en place un logique de mapping global, traiter les authentification des utilisateurs, etc.
app.delete()Va traiter les type de requête HTTP DELETE
app.get()Va traiter les type de requête HTTP GET
app.listen()Monte un serveur web sur un port particulier.
app.listen([port[, host[, backlog]]][, callback])
app.post()Va traiter les type de requête HTTP POST
app.put()Va traiter les type de requête HTTP PUT
app.render()Pemet d’utiliser un moteur de template
app.route()Permet d’utiliser une instance d’une simple route et d’y associe plusieurs middlewares spécifiques asociés à la route.
ex :
app.route(‘/events’)
.all(function (req, res, next) {
// runs for all HTTP verbs first
// think of it as route specific middleware!
})
.get(function (req, res, next) {
res.json({})
})
.post(function (req, res, next) {
// maybe add a new event…
})
Ceci pour centraliser les réponses à faire suivant les requêtes de type GET, POST ou autres pour un même chemin. Cela évite de faire des erreurs de doublons et clarifie le code
app.use()Déclare des middleware spécifiques

II.2 Request et Response

Les objets Request et Response concerne respectivement la requête web (resquest) et la réponse à faire (response).

Les méthodes/propriétés les plus utilisées de Request seront :

req.bodyobtenir les clefs/valeurs des données transmisses dans le body de la requête
req.hostnamenom du hostname
req.ipadresse ip
req.methodMéthode HTTP utilisée (GET, POST, etc.)
originalUrl, baseUrl, pathInformation sur le niveau des URL.
Exemple :
app.use(‘/admin’, function (req, res, next) { // GET ‘http://www.example.com/admin/new’
console.dir(req.originalUrl) // ‘/admin/new’
console.dir(req.baseUrl) // ‘/admin’
console.dir(req.path) // ‘/new’
next()
})
paramsPermet de récupérer des propriétés au sein d’une URL
Exemple pour un chemin déclaré de cette manière /user/:name
// GET /user/tj
console.dir(req.params.name)
// => ‘tj’
queryPermet de récupérer les variables indiquées dans l’url
Exemple :
// GET /search?q=tobi+ferret
console.dir(req.query.q) // => ‘tobi ferret’
// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
console.dir(req.query.order) // => ‘desc’
console.dir(req.query.shoe.color) // => ‘blue’
console.dir(req.query.shoe.type) // => ‘converse’
// GET /shoes?color[]=blue&color[]=black&color[]=red
console.dir(req.query.color) // => [‘blue’, ‘black’, ‘red’]

Les objets/méthodes les plus utilisées pour l’objet Response seront :

res.send()Envoi un flux html
res.render()Utilise un template (et/ou un moteur de template)
res.set()Définit les propriétés du header
res.redirect()Redirection
res.json()Renvoie une réponse sous forme json (header type modifié). Prend en paramètre plein de type de variables (string, tableau, etc)

La liste n’est pas exhaustive mais elle permet de commencer à prendre en main simplement ces 2 objets.

II.3 Exemple

Ci dessous quelques exemples d’implémentation

II.3.1 Exemple simple de gestion de routes

const express 	= require('express')

const app = express()  			// Instancie l'application express
app.set('view engine', 'ejs'); 	// associe le moteur de template Ejs à Express
const port = 8080


// Simple gestion d'accès à la racine
app.get("/", (req,res)=>{
	res.send("Bienvenue sur la page d'accueil")
})

// utilisation de route pour l'url "/admin" (gestion du GET et POST au même endroit)
app.route("/admin").get((req,res,next)=> {
	res.send("Page admin en GET")
}).post ((req,res,next)=> {
	res.json ("{'status' : 'ok'}")
})

// Cas des pages non présentes : utilisation de son propre middleware
//   mettre à la fin obligatoirement
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');	// force la sortie en texte
    res.status(404).send('Page introuvable !');		// status 404 et texte accompagnant
});

app.listen(port, () => {
  console.log(`Ecoute sur le port:${port} avec Express`)
})

II.3.2 Exemple de traitement d’un formulaire POST

Pour pouvoir récupérer simplement les données de POST, il faudra utiliser un middle-ware spécifique : body-parser.

Ce code récupère les informations envoyées par un formulaire puis affiche les données reçues sous forme JSON.



const express 	= require('express')
const path 		= require('path');
const bodyParser = require('body-parser');

const app = express()  			// Instancie l'application express
app.set('view engine', 'ejs'); 	// associe le moteur de template Ejs à Express
const port = 8080

// enregistrement du middleware bodyparser
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies


// utilisation de route pour l'url "/" (gestion du GET et POST au même endroit)
app.route("/").get((req,res,next)=> {
	
	// renvoie le contenu html du fichier /views/fomulaire.html
	res.sendFile(path.join(__dirname+'/views/formulaire.html'));

}).post ((req,res,next)=> {
	// renvoie sous forme json les paramètres reçus
	res.json (req.body)    // body est rempli par le middleware body-parser
})


// Cas des pages non présentes : utilisation de son propre middleware
//   mettre à la fin obligatoirement
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');	// force la sortie en texte
    res.status(404).send('Page introuvable !');		// status 404 et texte accompagnant
});

app.listen(port, () => {
  console.log(`Ecoute sur le port:${port} avec Express`)
})

Il est possible de ne pas passer par le middle-ware « body-parser ». lien montrant comment faire : https://www.geeksforgeeks.org/parsing-form-data-in-express-app-manually-without-body-parser/

  • exemple particulièrement intérresant pour comprendre et faire soi-même un middleware

II.3.3 Exemple de traitement d’un formulaire GET

Dans ce cas, le formulaire envoie les données vers /formulaire

const express 	= require('express')
const path 		= require('path');

const app = express()  			// Instancie l'application express
app.set('view engine', 'ejs'); 	// associe le moteur de template Ejs à Express
const port = 8080

app.get("/",(req,res)=> {	
	// renvoie le contenu html du fichier /views/fomulaire.html
	res.sendFile(path.join(__dirname+'/views/formulaire_get.html'));
})

app.get("/formulaire",(req,res)=> {
	// renvoie les variables du formulaires reçues sous forme JSON
	res.json(req.query)
})

// Cas des pages non présentes : utilisation de son propre middleware
//   mettre à la fin obligatoirement
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');	// force la sortie en texte
    res.status(404).send('Page introuvable !');		// status 404 et texte accompagnant
});

app.listen(port, () => {
  console.log(`Ecoute sur le port:${port} avec Express`)
})

II.3.4 Exemple de traitement d’upload d’un fichier

Pour pouvoir manipuler simplement les upload, il faut utiliser le middle-ware « express-fileupload ».

– Documentation : https://www.npmjs.com/package/express-fileupload

Une fois le formulaire lancé, coté node.js le fichier se trouveras dans l’objet req.files.

Exemple : si la balise est « <input name= »fic » type = « file »> » alors le fichier disponible sera sous node.js « req.file.fic »

Soit le formulaire suivant :

<html>
  <body>
    <form ref='uploadForm' 
      id='uploadForm' 
      action='http://localhost:8000/upload' 
      method='post' 
      encType="multipart/form-data">
        <input type="file" name="sampleFile" />
        <input type='submit' value='Upload!' />
    </form>     
  </body>
</html>

Et le code node.js :


const express 		= require('express')
const path 		= require('path')
const fileUpload 	= require('express-fileupload')

const app = express()  			// Instancie l'application express
app.set('view engine', 'ejs'); 	// associe le moteur de template Ejs à Express
const port = 8080

// enregistrmement du middle-ware upload : default options
app.use(fileUpload())

app.get("/",(req,res)=> {
	// renvoie le contenu html du fichier /views/fomulaire.html
	res.sendFile(path.join(__dirname+'/views/formulaire_upload.html'));
})

app.post("/upload",(req,res)=> {

	if (!req.files || Object.keys(req.files).length === 0) {
	    return res.status(400).send('No files were uploaded.');
	  }
	// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
	let sampleFile = req.files.sampleFile;
	// Use the mv() method to place the file somewhere on your server
	sampleFile.mv(path.join(__dirname,"upload/" + req.files.sampleFile.name), function(err) {
		if (err)
	    	return res.status(500).send(err);
	    res.send("Fichier '" + req.files.sampleFile.name +"'' uploadé");
	})
})


// Cas des pages non présentes : utilisation de son propre middleware
//   mettre à la fin obligatoirement
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');	// force la sortie en texte
    res.status(404).send('Page introuvable !');		// status 404 et texte accompagnant
});

app.listen(port, () => {
  console.log(`Ecoute sur le port:${port} avec Express`)
})

Ne pas hésiter à voir les options sur le site officiel : upload fichiers multiples, limitation taille, création répertoire parent, etc…

II.4 Les middlewares

II.4.1 Présentation des middlewares communs

Comme nous l’avons pu le voir, express permet l’utilisation de middle-ware. Qu’ils soient propres à l’application (midlle-ware application ou routeur) ou qu’ils proviennent de modules tiers (middle-ware tiers).

Ci-dessous une liste des middle-ware tiers à prendre en compte :

body-parserPermet de parser automatiquement les variables intégré dans le body d’une requête (ex :formulaires POST)https://github.com/expressjs/body-parser
compressionCompresse la sortie webhttps://github.com/expressjs/compression
cookie-sessionGère les cookies côté client et serveurhttp://expressjs.com/en/resources/middleware/cookie-session.html
express-debugPour debogguer plus facilement (ne pas utiliser en prod)https://github.com/devoidfury/express-debug
serv-staticAssocie une route à un dossier du projet. Cette route pourra directement donner accéder à tout ou partie du dossier (ex : /public)https://github.com/expressjs/serve-static
helmetSécurise les applications en définissant certaines propriétés du headerhttps://github.com/helmetjs/helmet

Ici une liste plus exaustive : https://github.com/expressjs

II.4.2 Exemple d’utilisation du middleware cookie-session


const express 		= require('express')
const path 		= require('path')
const cookieSession     = require('cookie-session')
const bodyParser 	= require('body-parser');

const app = express()  			// Instancie l'application express
app.set('view engine', 'ejs'); 	// associe le moteur de template Ejs à Express
const port = 8080


////////////////////////
// Enregistrement Middleware
///////////////////////

// enregistrement du middleware bodyparser
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

// Déclaration du middle-ware session
app.use(cookieSession({
  name: 'session_site',
  keys: ['maphrasesecrete'],

  // Cookie Options
  maxAge: 24 * 60 * 60 * 1000 // 24 hours
}))


//////////////////////
//  Route
////////////////////


// Accueil
app.get("/",(req,res)=> {
	
	// sesion existante
	if (req.session.auth==undefined) {
		// réinitialise les valeurs
		req.session.nom 	= ""
		req.session.prenom  = ""
		req.session.auth    = 0
		req.session.nb_tentative = 0
	}

	// session authentifié ?
	if ( req.session.auth==0) {
		// non : renvoi vers formulaire d'authentification
		res.redirect("/auth")
	} else {
		// oui : affichage page accueil personnalisée
		res.render("accueil2",{"session" : req.session})
	}	

})

// formulaire enregistrement
app.get("/auth", (req,res)=>{
	res.render("session",{"session" : req.session})
})

// deconnexion : réinitialisation des valeurs cookies
app.get("/deconnect", (req,res)=>{
	
	req.session.nom 			= null
	req.session.prenom 			= null
	req.session.auth 			= null
	req.session.nb_tentative 	= null
	res.redirect("/")
})


// vérification envoie données formulaire
app.post("/auth", (req,res)=>{

	// conditions pour être authentifié
	var continuer = 1
	if (req.body.nom != "nom") 			{continuer = 0}
	if (req.body.prenom != "prenom") 	{continuer = 0}
	
	// renseigne le cookie des valeurs données
	req.session.nom 	= req.body.nom
	req.session.prenom 	= req.body.prenom

	// authentifié ?
	if (continuer == 1) {
		// oui
		req.session.auth = 1
		req.session.nb_tentative = 0

	} else {
		// non
		req.session.auth = 0
		req.session.nb_tentative +=1
	}
	res.redirect("/")
})


// Cas des pages non présentes : utilisation de son propre middleware
//   mettre à la fin obligatoirement
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');	// force la sortie en texte
    res.status(404).send('Page introuvable !');		// status 404 et texte accompagnant
});



app.listen(port, () => {
  console.log(`Ecoute sur le port:${port} avec Express`)
})


II.5 Les bonnes pratiques

Rien à inventer, lire celles du site officiel :

III Module Ejs

C’est un module dédié au template. Il en existe plusieurs mais celui est assez simple à prendre en main.

Ce module s’intègre à expressjs très simplement. Ca principale force est de pouvoir intégrer du code javascript au sein du code HTML comme ce qu’il peut être fait avec PHP.

Il intègre également des include, ce qui permet de modulariser très facilement ses templates.

Pas d’exemple ici, le site officiel étant particulièrement bien détaillé en terme d’exemples.

Node.js : modules externes Express et EJS (routing et template)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *