Afin de conclure la série d’articles sur les API, je vous propose ici d’aborder un élément essentiel dans leur développement : le système de gestion de base de données (SGBD). Pour ce faire, nous allons reprendre le développement réalisé précédemment dans l’article intitulé : Développez votre propre API avec Node.js et Express, dans lequel je vous avais proposé un exemple d’API répertoriant les piscines de la métropole lilloise. Je vous invite donc à vous y référer car nous allons ici finaliser cette API en proposant un SGBD NoSQL : MongoDB.
MongoDB, un SGBD NoSQL
MongoDB est un système de gestion de base de données NoSQL (orienté document) en opposition avec les SGBD relationnels SQL traditionnels. Je ne m’attarderai pas sur la distinction entre les SGBD SQL et NoSQL, de nombreuses ressources sont disponibles à ce sujet. Retenez juste qu’à la différence des systèmes SQL qui reposent sur des tables relationnelles, MongoDB repose sur des collections de documents au format JSON (clé/valeur).
Pour nous plonger sans plus attendre dans l’application qui nous intéresse, vous trouverez ci-dessous l’exemple d’une collection contenant deux documents. Chaque document représente une piscine.
Afin de faciliter l’accès et les différentes opérations liées à la base MongoDB, nous allons utiliser un framework nommé Mongoose. Pour installer ce framework, rien de plus simple, il suffit d’entrer la commande (dans votre console) depuis le dossier restfrugal* :
npm install mongoose --save
*A ce stade, vous devriez avoir en héritage de l’article précédent, un dossier nommé restfrugal dans lequel se trouve le fichier apifrugal.js, contenant la logique de notre API.
Par souci de simplicité, nous utiliserons dans cet article une base MongoDB hébergée gratuitement, dans la limite de 500MB, chez mLab. Ce qui est largement suffisant dans notre cas et cela nous évite d’installer MongoDB sur notre poste. Si vous souhaitez tout de même l’installer sur votre poste, de nombreuses ressources sont disponibles sur le web.
Inscrivez-vous sur le site et créer une nouvelle base (choisir create new, ensuite cliquer sur single node et choisir Sandbox : FREE). Enfin, nommez la base ; nous la nommerons restfrugaldb (tout en minuscule) dans notre cas. Voilà, notre base de données à été créée. Dernière petite chose avant de pouvoir y accéder, nous devons créer un utilisateur. C’est dans la rubrique Users que cela se passe. Cliquez alors sur Add database user et entrez les informations demandées. Vous pouvez utiliser celle que j’ai créée pour ce tutoriel (userfrugal:passwordfrugal). Une fois cela fait, nous pourrons accéder à notre base de données via le lien suivant :
mongodb://userfrugal:passwordfrugal@ds151108.mlab.com:51108/restfrugaldb
Utilisation de Mongoose dans notre API
Reprenons le fichier apifrugal.js contenant la logique de notre API. Nous allons y ajouter quelques lignes de codes pour indiquer que nous allons utiliser le framework mongoose et inscrire l’adresse de notre base de données. Ensuite nous établissons la connexion avec la base.
//L'application requiert l'utilisation du module Express. //La variable express nous permettra d'utiliser les fonctionnalités du module Express. var express = require('express'); // Nous définissons ici les paramètres du serveur. var hostname = 'localhost'; var port = 3000; // La variable mongoose nous permettra d'utiliser les fonctionnalités du module mongoose. var mongoose = require('mongoose'); // Ces options sont recommandées par mLab pour une connexion à la base var options = { server: { socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } }, replset: { socketOptions: { keepAlive: 300000, connectTimeoutMS : 30000 } } }; //URL de notre base var urlmongo = "mongodb://userfrugal:passwordfrugal@ds151108.mlab.com:51108/restfrugaldb"; // Nous connectons l'API à notre base de données mongoose.connect(urlmongo, options); var db = mongoose.connection; db.on('error', console.error.bind(console, 'Erreur lors de la connexion')); db.once('open', function (){ console.log("Connexion à la base OK"); }); // Nous créons un objet de type Express. var app = express(); var bodyParser = require("body-parser"); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json());
Maintenant que nous nous sommes connectés à la base, nous allons implémenter chacune des méthodes (GET, POST, PUT, DELETE) de notre API. Avant cela, nous devons définir un schéma pour nos données. En effet, mongoose utilise des schémas pour modéliser les données.
// CODE // Pour modéliser les données, le framework mongoose utilise des "schémas" ; nous créons donc un modèle de données : var piscineSchema = mongoose.Schema({ nom: String, adresse: String, tel: String, description: String }); var Piscine = mongoose.model('Piscine', piscineSchema); //SUITE DU CODE
Nous allons ensuite utiliser ce schéma dans chacune des méthodes de notre API. Commençons par le plus simple : la méthode GET. Il s’agit dans ce cas d’interroger la base et de renvoyer à l’utilisateur la liste de toutes les piscines.
// Je vous rappelle notre route (/piscines). myRouter.route('/piscines') // J'implémente les méthodes GET, PUT, UPDATE et DELETE // GET .get(function(req,res){ // Utilisation de notre schéma Piscine pour interrogation de la base Piscine.find(function(err, piscines){ if (err){ res.send(err); } res.json(piscines); }; }) // SUITE DU CODE
Si aucune piscine n’est inscrite en base (ce qui devrait être le cas avec une base fraichement créée), la méthode GET devrait renvoyer un tableau vide. Voyons maintenant comment ajouter des piscines à notre base de données. Nous allons tenir compte de notre schéma Piscine pour fournir les informations attendues par la base. Nous avions vu dans l’article précédent comment récupérer les données envoyées par la méthode POST, c’est exactement ce que nous allons faire ici.
.post(function(req,res){ // Nous utilisons le schéma Piscine var piscine = new Piscine(); // Nous récupérons les données reçues pour les ajouter à l'objet Piscine piscine.nom = req.body.nom; piscine.adresse = req.body.adresse; piscine.tel = req.body.tel; piscine.description = req.body.description; //Nous stockons l'objet en base piscine.save(function(err){ if(err){ res.send(err); } res.send({message : 'Bravo, la piscine est maintenant stockée en base de données'}); }) })
Vous pouvez maintenant ajouter des piscines avec l’application Postman comme illustré ci-dessous :
Vous avez compris le principe. Pour le reste des méthodes, en particulier pour la méthode PUT, les opérations se feront sur une piscine que nous aurons identifiée par son identifiant dans l’URI. Encore une fois, je vous invite à vous référer à l’article sur le sujet, si tout cela n’est pas très clair. Ci-dessous les méthodes GET, PUT et DELETE pour une piscine identifiée.
myRouter.route('/piscines/:piscine_id') .get(function(req,res){ //Mongoose prévoit une fonction pour la recherche d'un document par son identifiant Piscine.findById(req.params.piscine_id, function(err, piscine) { if (err) res.send(err); res.json(piscine); }); }) .put(function(req,res){ // On commence par rechercher la piscine souhaitée Piscine.findById(req.params.piscine_id, function(err, piscine) { if (err){ res.send(err); } // Mise à jour des données de la piscine piscine.nom = req.body.nom; piscine.adresse = req.body.adresse; piscine.tel = req.body.tel; piscine.description = req.body.description; piscine.save(function(err){ if(err){ res.send(err); } // Si tout est ok res.json({message : 'Bravo, mise à jour des données OK'}); }); }); }) .delete(function(req,res){ Piscine.remove({_id: req.params.piscine_id}, function(err, piscine){ if (err){ res.send(err); } res.json({message:"Bravo, piscine supprimée"}); }); });
Voilà ! Nous avons une API fonctionnelle. Bien entendu, nous avons simplifié beaucoup de choses dans le développement de cette API, mais c’est déjà un très bon début pour se lancer dans un prototype de service. Si des choses vous ont échappées ou si vous souhaitez approfondir certains points, n’hésitez pas à nous laisser un commentaire. Je vous laisse ci-dessous l’intégralité du fichier apifrugal.js :
var express = require('express'); var hostname = 'localhost'; var port = 3000; var mongoose = require('mongoose'); var options = { server: { socketOptions: { keepAlive: 300000, connectTimeoutMS: 30000 } }, replset: { socketOptions: { keepAlive: 300000, connectTimeoutMS : 30000 } } }; var urlmongo = "mongodb://userfrugal:passwordfrugal@ds151108.mlab.com:51108/restfrugaldb"; mongoose.connect(urlmongo, options); var db = mongoose.connection; db.on('error', console.error.bind(console, 'Erreur lors de la connexion')); db.once('open', function (){ console.log("Connexion à la base OK"); }); var app = express(); var bodyParser = require("body-parser"); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); var piscineSchema = mongoose.Schema({ nom: String, adresse: String, tel: String, description: String }); var Piscine = mongoose.model('Piscine', piscineSchema); var myRouter = express.Router(); myRouter.route('/') .all(function(req,res){ res.json({message : "Bienvenue sur notre Frugal API ", methode : req.method}); }); myRouter.route('/piscines') .get(function(req,res){ Piscine.find(function(err, piscines){ if (err){ res.send(err); } res.json(piscines); }); }) .post(function(req,res){ var piscine = new Piscine(); piscine.nom = req.body.nom; piscine.adresse = req.body.adresse; piscine.tel = req.body.tel; piscine.description = req.body.description; piscine.save(function(err){ if(err){ res.send(err); } res.json({message : 'Bravo, la piscine est maintenant stockée en base de données'}); }); }); myRouter.route('/piscines/:piscine_id') .get(function(req,res){ Piscine.findById(req.params.piscine_id, function(err, piscine) { if (err) res.send(err); res.json(piscine); }); }) .put(function(req,res){ Piscine.findById(req.params.piscine_id, function(err, piscine) { if (err){ res.send(err); } piscine.nom = req.body.nom; piscine.adresse = req.body.adresse; piscine.tel = req.body.tel; piscine.description = req.body.description; piscine.save(function(err){ if(err){ res.send(err); } res.json({message : 'Bravo, mise à jour des données OK'}); }); }); }) .delete(function(req,res){ Piscine.remove({_id: req.params.piscine_id}, function(err, piscine){ if (err){ res.send(err); } res.json({message:"Bravo, piscine supprimée"}); }); }); app.use(myRouter); app.listen(port, hostname, function(){ console.log("Mon serveur fonctionne sur http://"+ hostname +":"+port); });
Si le sujet de l’innovation citoyenne vous intéresse et que vous souhaitez contribuer à améliorer les services de votre ville par le biais de ce genre de développement, sachez que nous sommes actifs au sein d’une association qui œuvre dans ce sens : le Citizen Clan. Et que vous êtes bien entendu les bienvenus. Ce sujet fait d’ailleurs l’objet d’un projet en cours.
Comme d’habitude, si des erreurs se sont glissées dans l’article, n’hésitez pas à nous en faire part.
Pour être informé des prochains articles, rendez-vous sur Twitter.
Merci, et à très bientôt sur Frugal Prototype
Ali Benfattoum
Intrapreneur, Tech Enthusiast, IoT Expert, Smart City Specialist…
Suivez moi sur @alifrugal
Related Posts
31 janvier 2017
Un bot Facebook Messenger pour la mobilité urbaine
Depuis quelques années, les bots, ces…
14 août 2016
Développez votre propre API avec Node.js et Express
Chose promise, chose due : nous allons…
bonjour,
si je veux changer localhost par mon adresse public afin que d’autres accèdent à mon service comme je procède
Bonjour Hamza,
Vous pouvez utiliser un service comme ngrok qui vous donnera une adresse publique pour votre localhost.
https://ngrok.com/
Bonjour Ali,
Je vous remercie grandement pour la clarté de vos articles ! Et l’aide que j’y trouve !
Je rencontre un léger problème lorsque je fais un POST et qu’ensuite j’affiche avec un GET les datas, j’ai en base ce type de réponse :
{
« _id »: « 5b24dc1518f24920293cffc4 »,
« __v »: 0
},
Avez-vous une idée d’où cela peut venir ?
Merci d’avance,
Alexandre
Bonjour Alex,
Pouvez-vous vérifier que le schéma mongoose est correct.
Bien à vous
Ali
Bonjour,
On dirait que votre requête POST envoyée par postman ne contient pas de données.
Pouvez-vous copier un example de requête POST que vous faites ?
Tony
bonjour ,
si jamais la piscine existe déjà dans la base, il ne faut pas créer deux !! dans ce cas comment faire la condition pour vérifié si elle existe pour qu’il ne l’ajoute pas ?
Bonsoir, quelqu’un pourrait m’aider s’il vous plait , j’ai une erreur(
Connected to MongoDB database
ReferenceError: Product is not defined
at api.post (/Users/dji/Desktop/projet_angular/appli/appli/backend/index.js:112:19)
at Layer.handle [as handle_request] (/Users/dji/Desktop/projet_angular/appli/appli/backend/node_modules/express/lib/router/layer.js:95:5)
)
Et voici le code:
//const Product = require(‘./product.model’);
const productSchema = new mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: String,
price : Number
});
var ProductModel = mongoose.model(‘Product’, productSchema);
api.post(‘/product’, (req, res, next) => {
//Le probleme est ici avec le new Product
const product = new Product({
_id: mongoose.Types.ObjectId(),
name: req.body.name,
price: req.body.price
});
product.save()
.then(result => {
res.send(‘kbjn,lk’);
})
.catch(err => {
console.log(err);
});
})
Superbe travail de vulgarisation ! Merci, très bien expliqué !
salut
dans un exemple pareil
var employeeSchema = new mongoose.Schema({
email: {
type: String
},
mdp: {
type: String
},
items: {
article: {
type: String
},
prix: {
type: String
}
}
});
commeent afficher uniquement les donnees des items (article et prix ) ?
et comment enregistrer les nouvelles donnees ?
merci