L'objectif des exercices de ce TD est de vous familiariser avec la création de programmes JavaScript côté serveur avec Node.js. Voir le cours en question.
Code de Livraison: H83W
1 - Mise en route
Sur les machines du bâtiment Bréguet
utilisez les postes sous Ubuntu pour ce TD.
- Si nécessaire, redémarrer l'ordinateur pour passer sous Ubuntu.
- Dans le répertoire "Documents" de votre compte, créer un répertoire spécifique dans lequel le code des différents exercices sera mis, comme par exemple "ExercicesNode".
A la fin du TD, n'oubliez pas de récupérer les fichiers que vous aurez créés, sinon ils seront effacés du disque automatiquement...
Sur votre machine perso
- Installer Node.js : https://nodejs.org
- Vous aurez besoin de la ligne de commande:
cmd.exe
sous Windows- Le "Terminal Mac" sous MacOS
- Quelques commandes:
cd
<nom-de-répertoire> : pour changer de répertoirels
(sous MacOS/Linux) etdir
(sous Windows) : pour voir les fichiers du répertoire courant- La touche [TAB] vous permet de completer automatiquement un nom de répertoire ou de fichier
- Il faudra vous déplacer avec la ligne de commande dans le répertoire où se trouve vos fichiers
Dans tous les cas
Assurez-vous de faire fonctionner les exemples du tuto NodeJS.
2 - Un Web Service avec Express
L'objectif de cet exercice est de transformer les quelques pages que nous avons créées en une application web sérieuse.
Notre application a besoin de faire deux choses:
- Fournir les pages html, css et javascript lors de la connection d'un client
- Garder sur le serveur les paramètres de configuration de notre application, et les délivrer sous la forme du fichier JSON que nous avions utiliser au dernier TD.
Le développement d'une application web avec Node peut être très fastidieuse, c'est pourquoi nous utiliserons la bibliothèque Express.js qui fournit un ensemble de fonctions facilitant le développement de ce type d'applications.
Si vous allez assez loin dans le TD, les données de configurations seront stockées dans une base de données SQLite3.
2.1 - Configuration et installation des bibliothèques Express
- Créez un nouveau répertoire MeteoNodeJs.
- Nous allons maintenant demander à NPM d'installer Express pour notre application.
- Si sur les machines du bâtiment Bréguet : configurez le proxy. En ligne de commande, tappez la commande
- En ligne de commande, placez-vous dans le répertoire puis tapez la commande:
- Observez le contenu de votre répertoire. Que contient-il maintenant ?
2.2 - Création de l'application Express
- Dans le répertoire "MeteoNodeJs", créez un fichier "server.js".
Créer une application Express qui écoute les requêtes HTTP est très simple. Il suffit d'instancier une application Express puis de définir les requêtes HTTP qu'elle accepte (et auxquelles elle répond), c'est-à-dire les "routes".
Dans notre cas, on voudra à terme deux "routes" : Une pour le contenu des page, et une pour le "service web" qui donnera la configuration sous forme JSON.
Import d'Express :
Dans le fichier "server.js", copier les lignes suivantes :
A ce stade vous pouvez essayer de démarrer votre application, mais puisqu'aucune route n'est encore définie celle-ci n'accepte encore aucune requête HTTP et vous ne pourrez donc pas la tester.
Définition d'une route :
Nous allons maintenant ajouter une "route", c'est-à-dire une requête HTTP que votre application va accepter et traiter. Une route est constituée de deux éléments : un verbe HTTP (par exemple : GET, POST, PUT…) et un chemin (par exemple : /voici/un/chemin, /chemin, /un/autre/long/chemin…).
- Ajouter au code précédent la route suivante, qui définit que l'application accepte une requête GET sur le chemin /meteo (l'application répond donc sur l'url http://localhost:8000/meteo) :
- Dans le corps de la fonction de callback de cette route, ajouter le code nécessaire pour que l'application réponde un texte de votre choix: par exemple, créez un fichier
test.txt
dans le répertoireMeteoNodeJs
et utiliserres.sendFile(__dirname+"/test.txt")
Test :
- Démarrer votre application en ligne de commande : dans le répertoire "MeteoNodeJs", taper
node server.js
. - Avec un navigateur, aller à l'url http://localhost:8000/meteo et observer le résultat.
- Notez que le nom du fichier est à priori complètement indépendant de l'url.
Note
Pour arrêter une version précédente de votre application qui tourne encore, taper ctrl+c dans le shell.
Pour que Node prenne en compte automatiquement les modifications faites sur votre application et que vous n'ayez pas besoin de la redémarrer, utilisez la commande nodemon au lieu de node pour lancer votre application : nodemon server.js.
2.3 - Ajout de contenu
Dans le cas qui nous intéresse, on souhaite que l'application délivre non pas un fichier texte idiot, mais par exemple la page principale meteo.html
de notre site. Une solution serait de remplacer "test.txt" par "meteo.html". Le problème en faisant cela serait que les autres resources: fichiers CSS, autres pages HTML, fichiers javascripts, ne seraient pas délivrés par l'application. Pour voir ce qui se passe:
Premiers pas
- Placez tous vos fichiers HTML, CSS et JS dans le repertoire "MeteoNodeJS".
- Si vous voulez, vous pouvez utiliser les miens.
- Dans la suite, je vais utiliser pour les exemples ces fichiers. Vous pouvez bien sûr utiliser les votres...
- Ouvrez le fichier
meteo.html
directement avec votre navigateur: admirez le magnifique CSS que j'ai intégré à la page. - Remplacez le contenu de votre fichier
server.js
par:
- Lorsque l'on se connecte au serveur à l'adresse
http://127.0.0.1:8000/meteo
, la page html est retournée. Par contre, rien d'autre n'est accèdé. Le CSS n'est en particulier pas chargé- Dans la console est affiché le contenu de la variable
req.url
: celle-ci comporte le chemin d'accès à la resource demandée par chaque connection. Vous devriez voir une liste de demandes dans le terminal (ici, on parle de la console de node.js, pas de la console du navigateur) - Celles-ci ne sont pas honorées car ne faisant pas partie de la route. C'est en particulier pour cela que le fichier CSS n'est pas chargé.
- Dans la console est affiché le contenu de la variable
Répondre à toutes les requêtes.
On va plutôt faire en sorte que la fonction de callback analyse l'url demandée, en récupérant les noms des resources demandées : Il faut donc
- modifier la route pour accepter tout ce qui serait sous la forme
127.0.0.1:8000/meteo/un/chemin/d/acces
- utiliser
req.url
pour récupérer/un/chemin/d/acces
.
Donc:
- Créez un sous-dossier
meteo
. - Placez les fichiers correspondant au site dans ce sous-dossier (donc tout sauf
server.js
etnode_modules
) - Changez la route pour
/meteo/*
(l'étoile signifie "n'importe quelle séquence de caractères") - Modifiez l'appel à
sendfile
pour qu'il récupère la bonne resource - Relancez le serveur
- Dans votre navigateur, accèdez à la page
127.0.0.1:8000/meteo/meteo.html
- En principe, tout est maintenant chargé et le magnifique CSS est bien utilisé.
- Dans votre navigateur, accèdez à la page
3 - Gérer les paramètres
Pour l'instant, on charge les préférence à l'aide d'un fichier JSON écrit en dûr. Ce fichier est à l'adresse /meteo/config.json
.
On va plutôt transformer la délivrance de ce contenu un "service web", qui sera généré automatiquement par le serveur. On va allouer pour cela une nouvelle route /config
À faire
- Créez dans
server.js
une nouvelle variable globale qui contient le contenu du fichier JSON:
- Créez une nouvelle route
/config
- La fonction de callback de cette nouvelle route va simplement renvoyer le contenu de la variable sous forme json. À la place de
res.sendfile
, on utilise la fonctionres.json(config)
. - Relancez le serveur, et testez avec votre navigateur en allant à l'adresse
127.0.0.1:8000/config
- modifiez l'appel à la fonction
.get
dans le fichier javascriptmeteo.js
: à la place de "config.json", utilisez "/config" (n'oubliez pas le "/" qui indique la racine de l'adresse). - Effacez votre fichier json et rechargez la page
127.0.0.1:8000/meteo/meteo.html
: en principe, l'appel à.get
doit s'effectuer et les bonnes choses doivent s'afficher.- Si vous utilisez l'exemple, si vous voyez des XXXX à la place des unités, c'est que cela ne marche pas...
4 - Rendons le fichier config.html
fonctionnel
Notre application météo possède un fichier que nous n'avons pour le moment pas développé outre mesure : le fichier config.html
. Nous allons remédier à cela dans cet exercice.
Il s'agit d'un formulaire qui permet en théorie de modifier les paramètres de configuration de l'application. Donc concrètement, les valeurs du formulaire doivent être envoyer au serveur qui les utilise pour changer sa variable globale config
.
4.1 - Remplissage du formulaire au démarrage
Lorsque vous chargez la page, celle-ci comporte un formulaire vide... C'est un peu agaçant: on aimerait que le formulaire reflète les choix contenus dans la variable config
du serveur. Pour cela, nous avons essentiellement deux choix:
- Utiliser un template au niveau du serveur pour générer une page
config.html
directement remplie - Avoir une page fixe, mais qui fait un appel AJAX lors de l'évenement
ready
au service web/config
et qui utilise les valeurs récupérées pour cocher les bonnes cases
Nous allons utiliser cette deuxième méthode, mais vous êtes invités à regarder les templates si cela vous intéresse. Il en existe beaucoup, par exemple allez voir ici pour une sélection possible.
À faire
- Chargez la page et assurez-vous que les valeurs correspondant à la variable
config
sont bien sélectionnées.
Note
Si vous utilisez les fichiers que je vous ai donné, vous aurez noté que chaque <select>
et chaque <input>
a un nom. Vous pouvez interragir avec en utilisant jQuery.
- Dans la console du navigateur, faites
et et pour voir.
- Essayez aussi
et
- Vous devriez en inférer comment modifier les valeurs du formulaire après l'appel au serveur
4.2 - Envoi des valeurs au serveur
La balise <form>
admet deux attributs intéressant:
action
: l'adresse à appeler en lui passant les paramètresmethod
: peut êtreget
oupost
. Essayez les deux et regarder le résultat: dans le premier cas, les valeurs du formulaire sont sur la ligne d'addresse. Dans l'autre, les valeurs sont "cachés" : elles sont dans le corps de l'appel HTTP.
Au niveau du serveur...
Derrière l'adresse à passer au formulaire se trouve le serveur: il faut qu'il réagisse correctement en mettant à jour la variable config
. On va définir une route spécifique pour cela.
- Définissez une nouvelle route
/set
, en mode GET, qui récupère le paramètremonparam
et affiche sa valeur:
- Relancez le serveur, et allez à l'adresse
http://127.0.0.1:8000/set?monparam=toto
avec votre navigateur. Relancez avec valeur autre que "toto". - Dans le fichier
config.html
, faitez que le formulaire appelle "/set
" en mode GET. - Modifiez la fonction de callback de la route
/set
pour qu'elle affiche l'un des paramètres. - Testez en ouvrant la page
config.html
et en utilisant le bouton<submit>
. - Au lieu de renvoyer du texte, faites une fonction de callback qui ressemble à cela:
- Testez : En principe, si vous modifiez un paramètre dans le formulaire et cliquez sur le bouton
<submit>
, le formulaire se recharge avec les bonnes valeurs. - Notez que cela n'est vrai que grace à l'appel à
ready
: si vous supprimer cet appel, le formulaire se rechargera vierge (essayez!) - Vous avez en principe maintenant une application "complète" : la page configuration est fonctionelle.
4.3 - Discussion
Le choix que nous avons fait dans cette implémentation est très "classique": le formulaire est équipé d'un bouton "submit" qui envoie les infos en mode POST et qui recharge la page. La page est "statique".
Un autre choix, plus moderne et "AJAX" dans l'esprit aurait été de ne pas utiliser de bouton "submit" mais de faire des appels asynchrones au serveur pour mettre à jour la variable globale config
à chaque modification d'un champ du formulaire.
Vous pouvez implémenter cette possibilité si vous le souhaitez, il n'y a à priori pas de difficultés particulières.
5 - Pour aller plus loin : Utilisation d'une base de donnée
Pour le moment, la configuration est stockée au niveau du serveur dans une variable. Si le serveur s'arrête, on perd les informations. On va dans cette exercice utiliser une base de donnée SQLite3 pour stocker et lire ces données. Voir le tuto sur SQlite3.
Le choix que nous faisons dans cet exercice est le suivant:
- Au démarrage du serveur, on va lire la base de donnée et initialiser la variable globale
config
- À chaque appel à la route
/set
, après mise-à-jour de la variable globaleconfig
on va mettre à jour la base de donnée.
Que mettre dans la base de donnée ?
- Il s'agit d'une base de donnée relationnelle, c'est-à-dire essentiellement un tableau. On pourrait donc mettre une ligne par parametre de configuration (une pour le vent, une pour la pression, etc...).
- Pour les besoin de la cause, c'est un peu lourd. On va simplement mettre une seule ligne dans la base de donnée, et associer à
default
une chaine de caractère qui sera le contenu de la variableconfig
.
5.0 - Vérifions que je ne mens pas
Vérifiez que relancer le serveur efface toutes les modifications !
5.1 - Installation de SQlite3
- Vous trouverez une version executable sur le site officiel. Placez l'executable dans le dossier dans lequel vous travaillerez.
- En ligne de commande, placez-vous dans le répertoire du serveur puis tapez la commande suivante:
- Potassez le tuto.
5.2 - Création d'une base de donnée config.db3
En utilisant le tuto, créez une nouvelle base de donnée config.db3
dans le répertoire MeteoNodeJS
:
5.3 - Connexion de l'application Express à la base de donnée townsdb.db3
- Dans le code de votre application, importez la bibliothèque SQLite3 pour Node :
- Puis créer une connexion sur la base de données contenue dans le fichier "townsdb.db3" :
- Quelle requête SQL permets de récupérer la configuration ? Testez-là avant dans le terminal avec la commande
sqlite3
. - Si vous faites
avec votre commande SQL vous devriez voir dans le terminal s'afficher la chaine JSON.
- Plutôt que de l'afficher, utiliser la fonction
JSON.parse(chaine-de-caractere)
pour définir la variableconfig
. - Maintenant, on est prêt à travailler: en principe, la variable
config
est chargée au démarrage du serveur par le contenu de la base de donnée. - La dernière chose à faire est de mettre à jour la base de donnée lors de l'appel à la route
/set
.- juste après la redéfinition de la variable
config
dans la fonction de callback, faites un appel à la base de donnée pour écrire avecJSON.stringify(config)
le contenu de la variableconfig
dans la base. Utilisez par exemple la commandedb.run("COMMANDE SQL")
avec la bonne commande. - Encore une fois, essayez avant en utilisant la ligne de commande sqlite3 pour valider votre commande.
- juste après la redéfinition de la variable
- Ouf ! Maintenant tout est complet. Si vous fermez le serveur puis le relancez, en principe la configuration est maintenant préservée !
Conclusion
L'application est très simple :
- il n'y a pas de notion d'utilisateurs
- la ville n'est pas configurable
- ...
On peut la complexifier à loisir. Néanmoins, dans cette série de TDs nous avons vu comment faire une application relativement complexe, avec un back-end qui fait appel à une base de donnée. C'est la base.
Pour aller plus loin:
- Pour gérer des utilisateurs, on pourrait utiliser des cookies de session, par exemple avec la librairie express-session.
- On pourrait aussi ajouter la ville en paramètre
- L'application pourrait aussi donner les prévisions...