Serveur Node.js
Node.js est une plate-forme de développement serveur en JavaScript. Node.js propose une programmation évènementielle non bloquante, ce qui permet de créer des applications temps-réel, tout en mutualisant le code JS entre client et serveur.
L’architecture de la plateforme est composée de :
- l’API Node qui est un ensemble de modules prêts à l’emploi : client et serveur HTTP, accès au système de fichiers, gestion des chemins sur l’OS, etc. Ces modules sont basés sur l’API CommonJS, afin de rendre le code d’un module interopérable sur différentes plateformes (navigateur, serveur, etc.). Il est bien entendu possible de créer ses propres modules CommonJS.
- la machine virtuelle V8 qui est un compilateur JavaScript (celui de Chrome)
- l’interpréteur Node qui permet d’exécuter le tout
Voici un exemple simpliste de serveur HTTP, qui retourne toujours le contenu du fichier index.html
situé à la racine du projet, et ce, peu importe la requête de l’utilisateur
let fs = require('fs');
let http = require('http').createServer((req, res) => {
fs.readFile(__dirname + '/index.html', (err, data) => {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}).listen(80);
$ node nom_du_fichier
npm#
npm
est le gestionnaire phare de modules Node. Il est souvent installé par défaut lors de l’installation de Node. Voici quelques commandes :
npm init
crée un nouveaupackage.json
npm (i)nstall [<package>]
installe le package demandé ou tous les packages listés danspackage.json
(dependencies
etdevDependencies
)npm (up)date [<package>]
mets à journpm start
exécute le scriptstart
npm run(-script) <script>
exécute le script demandénpm adduser
crée un nouvel utilisateurnpm publish
publie un nouveau module
Il existe également d’autres gestionnaires, comme yarn
(Facebook) ou pnpm
(performant npm, haha).
WebSockets#
Le prototcole WebSockets est une extension à HTTP, qui permet de créer une connexion ouverte bi-directionelle entre le serveur et les clients. Le serveur peut donc à tout moment envoyer une information au client, sans que celui-ci ne refasse de requête. Les WebSockets sont à la base du Push et rendent obsolètes les autres techniques comme l’AJAX long-polling.
Node.js simplifie énormément l’utilisation des WebSockets, et notamment le module socket.io
. Voici un chat simpliste mais temps-réel :
Exercice - Création d'un chat#
Partie serveur:
let fs = require('fs');
let http = require('http').createServer(function (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
}
);
});
let io = require('socket.io')(http);
http.listen(80);
io.on('connection', function (socket) {
socket.emit('welcome', { message: 'Vous êtes connecté au chat !' });
socket.on('message', function (data) {
console.log('Message: ' + data);
socket.broadcast.emit('message', {message: data});
});
});
Partie cliente:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
</style>
</head>
<body>
<h1>CHAT</h1>
<div id="websocket">
<form action="#" id="chatbox" >
<input type="text" name="message" placeholder="Votre message" />
<input type="submit" />
</form>
<div id="messages"></div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
let socket = io('http://localhost');
socket.on('welcome', function (data) {
afficheMessage(data.message);
});
socket.on('message', function (data) {
afficheMessage(data.message);
});
let form = document.getElementById('chatbox');
form.addEventListener('submit', function (e) {
socket.emit('message', form.elements['message'].value);
afficheMessage(form.elements['message'].value);
form.elements['message'].value = '';
e.preventDefault();
});
function afficheMessage (msg) {
let message = document.createElement('p');
message.innerHTML = msg;
document.getElementById('messages').appendChild(message);
}
</script>
</body>
</html>
Le code est basé sur socket.io, un module Node.js qui permet de gérer les WebSockets de manière simplifiée. Avant toute chose, il faut donc l'installer via npm (gestionnaire de modules Node.js), via la ligne de commande, déplacez-vous dans votre dossier, puis :
$ npm install socket.io
Pour lancer le serveur Node.js :
$ node server.js
Affichez la page http://localhost dans plusieurs onglets et/ou plusieurs navigateurs. Améliorez le chat:
- Demandez le nom de la personne avant connection au chat
- Modifiez les messages pour afficher le nom
- Affichez un message quand les personnes se connectent ou se déconnectent
- Ajoutez la fonctionnalité ("un utilisateur est en train de taper")
Express#
Express est un module npm qui nous apporte les fonctionnalités fondamentales d’un serveur web (gestion des requêtes, passage de paramètres, intégration de base de données, templating, etc.). Il simplifie et sécurise donc le développement d’un serveur Node
Base de données#
Il existe une multitude de systèmes de base de données sous Node, la plupart ayant des modules prévus pour Express.
Exercice - Node + Express + Mongo#
Le but de cet exercice est de créer une visualisation basique des restaurants de New-York.
- Créez une application express à l’aide du générateur d’application Express
- Créez un conteneur Docker pour cette base Docker mongoDB. Il faudra penser à exposer le port 27017 de ce conteneur pour que votre application node puisse y accéder.
docker run -d --name mongotsi -p 27017:27017 mongo
- Installez le module mongodb pour Node :
npm install mongodb --save
Première étape, la base de données :
-
Voici les données sources : restaurants.json
-
Copiez le fichier source dans le conteneur :
docker cp restaurants.json mongotsi:/
- Insérez les données :
docker exec -ti mongotsi mongoimport --db test --collection restaurants --drop --file /restaurants.json
Pour pouvoir faire des requêtes spatiales, n'oubliez pas de créer un index spatial sur l'attribut location:
- Connectez-vous à Mongo Shell:
docker exec -ti mongotsi mongosh
- Executez
db.restaurants.createIndex({ location: '2dsphere' })
Seconde étape, création du serveur
- Créez une route express nommée
data
- Connectez-vous à votre base de données Mongodb, (voir comment se connecter, puis comment chercher dans une collection), et retournez l’intégralité du résultat en JSON
- Testez l’URL de votre service depuis votre navigateur (attention, le fichier est volumineux)
- Pour limiter nos données, ajoutez à votre route un paramètre
:bbox
qui sera une chaine de caractères avec les latitudes/longitudes séparées par des virgules du rectangle de sélection respectant ce format : southwest_lng,southwest_lat,northeast_lng,northeast_lat - Traitez cette chaine puis modifiez votre requête pour sélectionner uniquement les restaurants inclus dans cette bbox. Voir https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/index.html. Attention au type (
String
vs.Number
) dans les spécifications du $box .
Ensuite, coté client (avec ou sans Vue)
- Créez une nouvelle carte Leaflet, centrée sur New-York (lat/lng 40.7/-73.9, zoom 16) dans la vue
index.pug
. Pug) - Au chargement, récupérez la bbox actuelle de votre carte en chaine de caractères (
bounds.toBBoxString()
) - Faites une requête vers
/data/<bbox>
et affichez les restaurants visibles (markers) (attention à l'ordre des coordonnées)
Enfin
- Lorsque l’on déplace la carte, on charge les restaurants de la nouvelle bbox, mais
- On n’affiche que les restaurants qui ne sont pas déjà présents (pour éviter les doublons)
- On enlève les restaurants qui ne sont plus visibles dans la bbox actuelle
- Pensez aux nouveautées ES6
Ressource supplémentaire : http://duspviz.mit.edu/web-map-workshop/leaflet_nodejs_postgis/