Une API REST sous NodeJS
Implémentez une API sous NodeJS pour distribuer vos données
Il faut voir une API comme un fournisseur d'information. Cette source n'est pas directement
destinée à un internaute mais plutôt a un programme qui saura en faire bon usage. On peut, par
exemple, imaginer une API qui renvoie le cours actuel de l'euro, ou encore la ville correspondant
à un code postal en particulier. Dans tous les cas, l'application à l'origine de la requête est
consommatrice de l'information et rarement partie prenante dans sa mise à jour.
Nous avons vu dans des articles précédents comment charger un fichier CSV sous NodeJS et comment
implémenter un serveur express. Les liens ci-dessous renvoient à ces deux articles pour
information :
Chargement des données sous NodeJS
Serveur WEB sous NodeJS
Ici nous allons combiner le tout pour créer une API chargée de renvoyer à tout programme qui le demande un dataset, en l'occurrence celui de salaires par secteur d'activité, sous forme de structure JSON.
Présentation des données
Les données que nous allons exploiter proviennent d'un dataset regroupant les salaires et secteurs d'activité d'un certain nombre d'affiliés à une mutuelle. Le dataset compte 3 colonnes : Id, salaire et secteur d'activité. Il se présente sous la forme d'un fichier CSV de 206 observations plus 1 ligne d'en-tête. Notre API devra par conséquent charger ce fichier CSV dont vous trouverez ci-dessous un aperçu :
Id;Salaire;Secteur 1;15500;Restauration 2;20500;Restauration 3;21500;Restauration 4;23500;Transport 5;25500;Construction 6;25500;Construction 7;25500;Construction 8;26500;Restauration
Notez que nos données auraient tout aussi bien pu se trouver dans une base de données, auquel cas l'API aurait eu à sa charge d'établir une connexion puis une requête sur celle-ci. Nous verrons ce cas dans un article ultérieur.
Implémentation du serveur
Nous allons utiliser le framework express, il nous faut par conséquent l'installer avant toute chose.
npm install express --save
Nous reprenons ensuite le squelette du serveur implémenté lors de l'article traitant de ce sujet. Voici la base sur laquelle nous allons travailler.
//Chargement express et declaration des parametres du serveur
const express = require('express')
const server = express()
const host = '127.0.0.1';
const port = 3280;
server.get('/', (req, res) => {
res.send('Bienvenue a la racine !')
})
server.listen(port, host, () => {
console.log(`Server running at http://${host}:${port}/`);
});
Nous allons maintenant ajouter 3 choses : la source et les options permettant de lire le fichier contenant le dataset, l'instanciation d'un évènement de fin de lecture et enfin une fonction de chargement des données. Voici le code du serveur mis à jour :
//Chargement express et declaration des parametres du serveur
const express = require('express')
const server = express()
const host = '127.0.0.1';
const port = 3280;
//Chargement des modules de traitement des donnees
const Event = require('events');
const File = require('fs');
const csv = require('csv-parser');
//Declaration des constantes et variables
const fileName = "../data/salaires_par_secteur.csv";
const separator = ";";
const skipLines = 1;
const csvOptions = {'separator': separator,
'skipLines': skipLines,
'headers': false};
var df = [];
//Instanciation d'un evenement
const event = new Event();
function readData(res){
//Generation du flux de chargement
File.createReadStream(fileName)
.pipe(csv(csvOptions))
.on('data', (data) => df.push({'Id' : String(data[0]),
'Salaire': String(data[1]),
'Secteur' : String(data[2]),}))
.on('end', () => {res.status(200).send(df);})
}
server.get('/', (req, res) => {
res.send('Bienvenue a la racine !')
})
server.listen(port, host, () => {
console.log(`Server running at http://${host}:${port}/`);
});
Nous y sommes presque, il nous reste à définir une nouvelle route sur laquelle nous dirigerons notre
serveur pour toute requête concernant les salaires. Nous allons appeler cette route "salaires" et la faire
pointer sur notre fonction readData. Vous noterez que nous avons pris soin de passer l'instance de la réponse
http (notée res) envoyée par express.
Voici la route à ajouter sous celle de la racine :
server.get('/salaires', (req, res) => {
readData(res);
})
Lançons le serveur et constatons ce que nous affiche un navigateur lors d'un appel direct à l'url : http://127.0.0.1:3280/salaires
[{"Id":"1","Salaire":"15500","Secteur":"Restauration"}, {"Id":"2","Salaire":"20500","Secteur":"Restauration"}, {"Id":"3","Salaire":"21500","Secteur":"Restauration"}, {"Id":"4","Salaire":"23500","Secteur":"Transport"}, {"Id":"5","Salaire":"25500","Secteur":"Construction"}, {"Id":"6","Salaire":"25500","Secteur":"Construction"}, .....
Implémentation d'un client
Notre propos, dans cet article, est de constater que l'API fonctionne. C'est pourquoi nous allons nous contenter
d'un client minimum.
Nous allons créer un nouveau fichier html (dashboard.html par exemple) puis implémenter dans une section body le script du client comme ceci (sans oublier de l'encadrer de balises "script" bien sûr) :
fetch('http://127.0.0.1:3280/salaires', {
method: 'GET',
headers: {
'Accept': 'application/json',
},
})
.then(response => response.json())
.then(response => console.log(JSON.stringify(response)))
Comme vous le voyez, nous n'éditons rien à l'écran mais nous appelons simplement notre API via un fetch. Nous récupérons
la réponse que nous envoyons dans la console.
Dans un navigateur web il nous reste à requêter notre page. Sans surprise, rien de va s'afficher. Il faut nous rendre dans la
console via les outils de développement pour constater l’édition des données :

CORS policy: No 'Access-Control-Allow-Origin'
Il y a fort à parier que vous avez obtenu ce message. Il s'agit en effet d'un excès de zèle des navigateurs qui cherche à vous protéger contre des attaques de type CSRF ou injection de requêtes illégitimes par rebond. Certains vous recommanderont d'installer une extension à votre navigateur pour désactiver ou du moins autoriser les origines multiples. Ce remède s'il s'avère efficace dans le cas d'un test local posera problème pour les utilisateurs désireux d'utiliser les services de votre API. Vous pourrez, en effet, difficilement demander à tout le monde d'installer une telle extension. La solution consiste à modifier légèrement notre serveur afin d'y ajouter, via la methode use, une modification de l'en-tête de la réponse. Voici le code complet ci-dessous :
//Chargement express et declaration des parametres du serveur
const express = require('express')
const server = express()
const host = '127.0.0.1';
const port = 3280;
//Chargement des modules de traitement des donnees
const Event = require('events');
const File = require('fs');
const csv = require('csv-parser');
//Declaration des constantes et variables
const fileName = "../data/salaires_par_secteur.csv";
const separator = ";";
const skipLines = 1;
const csvOptions = {'separator': separator,
'skipLines': skipLines,
'headers': false};
var df = [];
//Instanciation d'un evenement
const event = new Event();
function readData(res){
//Generation du flux de chargement
File.createReadStream(fileName)
.pipe(csv(csvOptions))
.on('data', (data) => df.push({'Id' : String(data[0]),
'Salaire': String(data[1]),
'Secteur' : String(data[2]),}))
.on('end', () => {res.status(200).send(df);})
}
server.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
server.get('/', (req, res) => {
res.send('Bienvenue a la racine !')
})
server.get('/salaires', (req, res) => {
readData(res);
})
server.listen(port, host, () => {
console.log(`Server running at http://${host}:${port}/`);
});
Il ne vous reste plus qu'à relancer le serveur et constater enfin l’édition des données dans la console. La prochaine étape sera de consommer ces données afin de dresser des graphiques via des librairies comme Plot, Chartjs ou encore d3js.
Retrouvez dans la rubrique "Nos datasets" toutes les données dont vous aurez besoin pour tester et pratiquer !