CentraleSupélecDépartement informatique
Gâteau du Glouton
3 rue Joliot-Curie
F-91192 Gif-sur-Yvette cedex
Micro-Service en Javascript avec NodeJS

L'objectif de cette partie est de réaliser un micro-service web de dépot et d'accès à des messages texte, en utilisant NodeJS. Pour la complétude de la chose, nous utiliserons front-end de type "Message Board" réalisé lors de la partie HTML+CSS+Javascript.

Résumé des resources

Ressources sur HTML + CSS:

Ressources sur Javascript:

Les transparents du dernier cours.

Code à rendre sur Edunao

1 - NodeJS

2.1 - Configuration

Clonez le repl https://repl.it/@kindjob5578/MessageBoard.

Observez les différentes parties:

  • Dans la zone "fichiers", vous avez un fichier index.js : c'est le code javascript exécuté par NodeJS. Il pourrait y avoir pleins 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: son adresse (temporaire) est accessible à cet endroit.
  • 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 index.js.

À l'inverse d'un serveur purement statique, ici vous avez les manettes pour décider de comment votre serveur réagit aux requêtes HTTP: tout se programme dans index.js.

D'ailleurs, vous noterez que pour le moment, la page répond "Cannot GET /". Pour ce qui nous intéresse, on ne va pas créer une route /... Vous pouvez si cela vous amuse ceci dit.

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 juste avant app.listen(...) la route suivante, qui définit que l'application accepte une requête GET sur le chemin /test/[quelquechose]
app.get('/test/*', function(req, res) {
    //ici construire la réponse HTTP
});

La fonction (non-nommée) est appelée quand un client se connecte à l'adresse en question. Le corps de la fonction a accès aux deux variables passées en argument: req et res. Le premier contient les infos de la requête, le deuxième est l'objet réponse à construire. Il possède une méthode très utile: res.json(objet-javascript) qui construit une réponse HTTP contenant un fichier JSON décrivant l'objet passé en argument.

  • Utilisez cette méthode pour rendre un object javascript, par exemple {"a": 1, "b" : 2}. Dans la suite, essayez aussi avec ["Hello", "World"]. Et avec 42.
    • Appuyez (ou ré-appuyez) sur "Run".
    • Allez à l'url de votre site en demandant la ressource "/test/quelquechose" et observez le résultat.
    • Notez que le fichier JSON retourné correspond à l'objet passé en argument.
  • On va maintenant utiliser ce qui est passé dans l'adresse.

Note

Quand vous faites des changements dans index.js, il faut "relancer" NodeJS en appuyant sur "Run"

2.3 - Un micro-service avec un état

Nous allons réaliser un micro-service maintenant un état au sein du serveur. L'état sera un entier, initialisé à zéro au démarrage du serveur.

On veut deux routes /cpt/inc et /cpt/query, avec les comportements suivant:

  1. /cpt/query : rends un fichier json avec la valeur du compteur
  2. /cpt/inc : incrémente de 1 la valeur du compteur, retourne un fichier json avec l'objet {"code" : 0}
  3. /cpt/inc?v=XXX : deux cas :
    • XXX est bien un entier : incrémente de XXX la valeur du compteur et retourne un fichier json avec l'objet {"code" : 0}
    • XXX n'est pas un entier : ne touche pas au compteur et retourne {"code" : -1}

Vérifiez que vous pouvez incrémenter le compteur de l'un-e de vos collègue, et inversement.

Note

  • On peut accèder aux arguments (ici "v" par exemple) à l'aide de req.query. Par exemple, essayez la route
app.get('/blah*', function(req, res) {
  console.log(req.query)
});

et allez voir à l'address votre-serveur/blah?key1=value1&key2=value2

  • Pour vérifier si une chaine de caractère correspond à une expression régulière, vous pouvez utiliser match. Par exemple:
"aba".match(/^[a-z]+$/)

rend vrai, et

"abA".match(/^[a-z]+$/)

rend faux.

2.4 - Micro-service de gestion de messages

Avec notre serveur on souhaite pouvoir faire au minimum cinq choses:

  1. Ajouter un message à la liste des messages
  2. Récupérer un message par son numéro
  3. Récupérer TOUS les messages
  4. Récupérer le nombre de messages postés
  5. Effacer un message de la liste

On va donc faire 4 routes:

  1. /msg/post/[le-message-à-poster]
  2. /msg/get/[le-numéro-du-message]
  3. /msg/getAll
  4. /msg/nber
  5. /msg/del/[le-numero-du-message]

et on va stocker les messages dans une variable sur le serveur.

Note

  • Pour pouvoir tester facilement l'interface avec un navigateur, je vous propose de tout faire avec des appels GET. Poster un message serait (à terme) plus naturel avec un appel POST bien sûr.
  • L'un des problème est alors le préchargement automatique des requêtes GET... Comme par exemple ce que Safari fait.
    • Préférez Chrome ou Firefox pour les tests directement avec la barre d'adresse

À faire

  • Créez dans index.js une nouvelle variable globale qui contiendra les messages:
var allMsgs = ["Hello World", "foobar", "CentraleSupelec Forever"]
  1. Créez une nouvelle route /msg/get/*
    • Supposons que le message 42 est "FOOBAR". La fonction de callback correspondant à une route /msg/get/42 va renvoyer un JSON sous la forme
{ "code": 1, "msg" : "FOOBAR" }
  • Si il n'y a pas de message 42 (ou si on a entré quelque chose qui n'est pas un entier), la fonction de callback va rendre
{ "code": 0 }
  • Note: parseInt() est votre ami pour changer une chaine de caractères en entier.
  • À la place de res.sendFile, on utilise la fonction res.json(objet-javascript).
  1. De façon similaire, réalisez les autres routes: /msg/nber rendra simplement un entier (la taille de la liste), /msg/getAll un tableau de string, et /msg/post/[un message] pourra simplement retourner le numéro du nouveau message posté.
    • Le message contient éventuellement des caractères d'échappement (par exemple %20 pour un espace). Vous pouvez retrouver la chaine de caractères originelle avec la fonction unescape("hello%20world")
  2. Testez vos méthodes:
    • Poster 2 messages
    • Vérifiez avec un appel à /msg/get/xxx que vous obtenez bien le résultat attendu.
    • Testez de manière similaire les autres routes.

3 - Rendre le Mock-up vivant !

Notre objectif est de connecter le site de dépot de message du premier TP avec ce micro-service de gestion de messages.

Pour cela, on va faire des appels AJAX (Asynchronous Javascript XML... sauf qu'on va manipuler du JSON en fait).

3.1 - Prise en main

Nous allons faire usage de la méthode fetch et des "promesses", comme discuté en cours. La forme du code qui va nous intéresser est comme suit:

fetch('https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=22e21ef649526ef2b1be4db6d2b0857d&mode=json')
.then(function(response) {
  return response.json();
})
.then(function(data) {
  alert(data.weather[0].description)
});

La méthode fetch va générer en tache de fond un appel asynchrone à l'adresse indiquée. Puis, lorsque la réponse aura été reçue, la série des then va être exécutée:

  • D'abord on récupère le json associé à la réponse
  • puis on utilise le json en question

Note

On ne peut pas utiliser directement utiliser response.json(): il s'agit d'une... promesse, à ouvrir avec le .then qui vient après.

À faire

  • Copiez-collez ce code dans le fichier script.js du repl de Mockup.
    • Changez l'adresse pour celle de votre micro-service de message, sur la route msg/getAll
    • modifier l'appel à alert pour récupérer le premier message
  • "Lancez" la page du mockup: un pop-up avec le premier message du micro-service doit apparaitre.

3.2 - Remplissage des messages

Essentiellement, ce dont on a besoin au chargement de la page est d'ajouter les messages dans l'ordre. Vous avez réalisé cela dans le premier TP, en utilisant une variable locale.

À faire

Modifiez votre code pour peupler la liste des messages en utilisant le résultat à l'appel AJAX de votre micro-service de messages.

3.3 - Publication d'un nouveau message

Dans la page web "index.html", on veut pouvoir faire quelque chose lorsque le bouton d'envoi de message est sélectionné.

Lors de votre premier TP, vous avez du utiliser un <button> avec une capture d'évenements du click de souris.

À faire

  • Mettez à jour le corps de la fonction pour poster le message du <textarea> à l'aide du micro-service correspondant
    • le texte correspondant peut être récupéré en javascript avec $("textarea").val()
  • Dans un deuxième temps, mettez à jour la liste des messages sur la page.
  • Vous devriez maintenant avoir une page fonctionnelle, interagissant avec le micro-service de messagerie.

3.4 - Modularité du setting

Vos collègues devraient avoir les mêmes conventions, vous pouvez même utiliser votre page pour récupérer leurs messages (et eux les votres).

Vous devriez pouvoir rendre la page paramétrique sur l'adresse du micro-service, en ajoutant un champ de texte pour la stocker.

3.5 Déploiement

Afin de pouvoir rendre votre micro-service web et votre appli-web de messages disponibles en ligne, il faut un service de déploiement. J'ai essayé https://render.com/ qui est simple à mettre en oeuvre. On peut créer un service statique et/ou un service web, qui sont ce qui nous faut. Chacun est attaché à un dépot github ou gitlab.

Rendu

Je veux

  • un ensemble serveur/client fonctionnel
    • pour une appliweb de partage de messages
  • une extension, à votre discrétion : ajout d'images, utilisateurs, etc...
  • un déploiement sur par exemple http://render.com

Livrable

  • Un petit rapport qui décrit ce qui a été fait
  • Les liens github/gitlab des projets
  • Les liens du déploiement et éventuellement des projets replit.