CentraleSupélecDépartement informatique
Gâteau du Glouton
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
TD Mercredi — NodeJS

L'objectif de cette partie est de vous permettre de réaliser un service web pour la partie configuration de l'appli web. (Voir le tuto en rapport et les slides)

Notre application a besoin de faire deux choses:

  1. Fournir les pages statiques html, css et javascript lors de la connection d'un client
    • Ceci est réalisé par le premier mini-site que vous avez implémenté
  2. Garder sur le serveur les paramètres de configuration de notre application, et les délivrer sous la forme du fichier JSON
    • Ceci va être réalisé par un micro-service

On aura donc 2 serveurs web, un par projet:

En effet, chaque projet est en fait un serveur, qui possède sa propre adresse. Dans un mode "développement" comme le cas présent, l'adresse du serveur est générée automatiquement (avec une chaine de caractères aléatoires). Sur l'image ci-dessous, on peut voir le lien en cliquant sur le bouton entouré en rouge et ouvrir la page en question en cliquant sur le bouton entouré en jaune:

Attention

Dans le mode développement, les liens ne fonctionnent que lorsque la page du projet repl.it est ouverte. Par ailleurs, les liens changent régulièrement, il faut donc vérifier que ceux-ci sont les bons si on fait des appels Ajax.

Pour la livraison à la fin de la journée

Sur Edunao !

1 - Un micro-service pour la configuration

Le développement d'une application web avec Node peut être simplement mis en oeuvre avec la bibliothèque Express.js qui fournit un ensemble de fonctions facilitant le développement de ce type d'applications.

1.1 - Configuration

Clonez le repl https://replit.com/@CSappliWeb2022/ConfigMeteo.

Observez les différentes parties:

  • Dans la zone "fichiers", vous avez un fichier server.js : c'est le code javascript exécuté par NodeJS. Il pourrait y avoir d'autres fichiers
  • En dessous de ce fichier, il y a les fichiers de configuration du programme NodeJS. Ils sont apparu car j'ai avant installé pour vous la librairie express. Vous pouvez en installer d'autres...
  • À droite, il n'y a pour le moment qu'une console qui dit "Node" : ce n'est pas la console du navigateur mais celle du programme NodeJS.

Pour l'instant le programme ne tourne pas. Lancez le programme en appuyant sur "Run".

  • Maintenant au dessus de la console vous avez la racine de votre site. On peut modifier la ressource envoyer des requètes GET au serveur. Comme pour le projet précédent, le serveur possède un lien qui peut être ouvert indépendamment.
  • En dessous, vous avez toujours la console NodeJS. Le programme s'exécute: "App listening on port 8080..." s'affiche. C'est la commande de la ligne 9 dans server.js.

À l'inverse d'un repl purement statique comme la dernière fois, ici vous avez les manettes pour décider de comment votre serveur réagit aux requêtes HTTP: tout se programme dans server.js. En particulier, si vous n'aimez pas le fait que le fichier racine soit index.html, pointez la racine sur un autre !

D'ailleurs, vous noterez que pour le moment, la page répond "Cannot GET /". On va changer cela.

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:

(:brush=javascript:) app.get('/', function(req, res) {

    //ici construire la réponse HTTP

}); (:endbrush:)

  • 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. Utiliser pour cela la commande res.send("du texte");

Test

  • Appuyez (ou ré-appuyez) sur "Run".
  • Regardez dans le panneau en haut à gauche, ou allez à l'url de votre site et observez le résultat.

Note

Quand vous faites des changements dans server.js, il faut "relancer" NodeJS.

1.2 - Notre serveur comme un service

Pour l'instant, on charge les préférence à l'aide d'un fichier JSON écrit en dur.

On va plutôt transformer la délivrance de ce contenu en un "service web", qui sera généré automatiquement par le serveur nouvellement créé. On va allouer pour cela une nouvelle route /config.

(:brush=javascript:) app.get('/config', function(req, res) {

   ...

}); (:endbrush:)

À faire

  • Créez dans server.js une nouvelle variable globale qui contient le contenu du fichier JSON:

(:brush=javascript:) var config = {

    "temp": {
        "unite": 1,
        "state": 1
    },
    "pression": {
        "unite": 1,
        "state": 1
    },
    "nuage": {
        "visib": {
            "unite": 0,
            "state": 1
        },
        "status": 1
    },
    "vent": {
        "unite": 0,
        "state": 1
    }

} (:endbrush:)

  • Créez une nouvelle route /config comme indiqué.
  • La fonction de callback de cette nouvelle route va simplement renvoyer le contenu de la variable sous forme json. À la place de res.send, on utilise la fonction res.json(config).
  • Relancez le serveur, et testez avec votre navigateur en allant à l'adresse https://xxx.xxx.repl.dev/config
  • modifiez l'appel à la fonction fetch dans le fichier javascript meteo.js: à la place de "config.json", utilisez "https://xxx.xxx.repl.dev/config" (n'oubliez pas le "/" qui indique la racine de l'adresse).
  • Effacez votre fichier json et rechargez votre site : en principe, l'appel à fetch 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...

2 - 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 vont être envoyées au micro-service qui les utilise pour changer sa variable globale config.

3.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:

  1. Utiliser un template au niveau du serveur pour générer une page config.html directement remplie
  2. Avoir une page fixe, mais qui fait un appel AJAX lorsque la page est chargée 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...

À faire

  • Chargez la page et assurez-vous que les valeurs correspondant à la variable config sont bien sélectionnées.

3.2 - Envoi des valeurs au serveur

La balise <form> admet deux attributs intéressant:

  • action : l'adresse à appeler en lui passant les paramètres
  • method : peut être get ou post. 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ètre monparam et affiche sa valeur.

(:brush=javascript:) app.get('/set', function(req, res) {

  if("monparam" in req.query) {
    var txt = "Donnee reçue :" + req.query.monparam;
    res.send(txt);
  } else {
    res.send("pas de paramètre monparam");
  }

}); app.get('/config', function(req, res) {

   ...

}); (:endbrush:)

  • Relancez le serveur, et allez à l'adresse http://xxx.xxx.repl.dev/set?monparam=toto avec votre navigateur. Relancez avec une 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:

(:brush=javascript:) app.get('/set', function(req, res) {

  // Mise à jour de la variable config
  config.XXX  =  req.query.XXX
  config.YYY  =  req.query.YYY
  ...

  // Redirigez vers config.html
  res.redirect("/config.html");

}); (:endbrush:)

  • 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 si vous chargez le script APRÈS le chargement de la page : si vous placez le script dans l'entête du document sans attendre l'évenement load, le formulaire se rechargera vierge (essayez!)
  • Vous avez en principe maintenant une application "complète" : la page configuration est fonctionelle.

3.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.

Conclusion

L'application est très simple :

  • il n'y a pas de notion d'utilisateurs
  • la ville n'est pas configurable
  • le site n'est pas déployé !
  • ...

On peut la complexifier à loisir. Néanmoins, dans cette série de TDs nous avons vu comment faire une application relativement complète, 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...