DEV Community

Cover image for NodeJS + Express partie 6 : Base de données MongoDB
 Eric Le Codeur
Eric Le Codeur

Posted on

NodeJS + Express partie 6 : Base de données MongoDB

Voici une série d'articles qui vous permettra créer des applications backend avec NodeJS + Express.

Cette série est la suite de ma série sur les bases de NodeJS. Si vous n'avez pas les connaissances de bases en NodeJS lisez cette série d'abord : Introduction à NodeJS

Node.js est aujourd'hui un incontournable, il est donc essentiel pour un développeur de le maitriser.

Je vais donc publier un nouvel article environ au deux jours et petit à petit vous apprendrez tout ce qu'il y a à savoir sur Node.js + Espress

Pour ne rien manquer suivez moi sur twitter : https://twitter.com/EricLeCodeur


Base de données MongoDB

Dans cette section nous allons apprendre comment manipuler une base de données MongoDB à partir de notre API.

Vous savez sans doute qu'il existe plusieurs type de base de données comme les base de données SQL et les base de donnée NoSQL.

Le but de cette article n'est pas d'expliquer en détail qu'est-ce qu'une base de données et comment elle fonctionne à l'interne. Donc un minimum de connaissance en base de données est requis.

Aujourd'hui, nous allons utiliser MongoDB qui est une base de données NoSQL

Les base de données NoSQL contiennent des collections qui eux contiennent des documents. Par exemple une base pourrait avoir la collection User et plusieurs documents qui contiendrait chacun les informations d'un user comme par exemple : no, nom, prénom, etc.

Si vous avez de l'expérience avec des bases de données SQL, on pourrait simplifier le tout en disant que les collections sont les tables et les documents sont les lignes et colonnes de la tables.

Installation MongoDB

MongoDB peut être installé sur votre machine local ou être utilisé en version cloud database.

Dans ce tutoriel nous allons créer une base de donnée MongoDB à partir de leur cloud. (https://www.mongodb.com/atlas)

Le service est gratuit et ne nécessite pas de carte de crédit.

Pour avoir accès au cloud MongoDB et ensuite pouvoir créer votre propre base de données, rendez-vous au https://www.mongodb.com/atlas et cliqué sur le bouton "Try Free".

Choisir le service Atlas, remplir le questionnaire et cliquer "Get started free"

Une fois votre compte créé, rendez-vous sur le panneau de configuration, vous devriez voir quelque chose comme cela.
Image description

Cliquez sur "Build a Database", ensuite choisir l'option "Free Shared" et cliquer sur "Create". Ensuite, conserver les options par défaut sauf la dernière option qui est "Cluster Name" et changer le nom pour "NodeExpress". Enfin cliquer sur "Create Cluster"

Créer une base de données

Votre compte MongoDB est créer et activé nous allons maintenant créer notre base de donnée et notre première collection

Votre cluster étant maintenant créer, vous devriez voir quelque chose comme cela
Image description

Pour créer une base de données et une collection. Cliquer sur "Browse Collection", ensuite sur "Add My Own Data". Enfin saisir le nom de la base de données et le nom de la collection et cliquer sur "Create"

Image description

Prêt à coder

Pour résumer, nous avons créé un compte cloud MongoDB, créer un free Cluster et créer notre première base de donnée "Demo" et enfin notre première collection "Products"

Maintenant nous sommes prêt pour coder notre API et manipuler notre base de données

Création du projet NodeJS

Nous allons maintenant créer notre projet NodeJS, je vais donner ici le code de départ (qui provient des articles précédant).

Créer un dossier

$ mkdir demo-express-mongo
$ cd demo-express-mongo
Enter fullscreen mode Exit fullscreen mode

Ensuite, installation du package ExpressJS et nodemon

$ npm install express
$ npm nodemon
Enter fullscreen mode Exit fullscreen mode

À noter que comme spécifié dans la section sur NodeJS, le package nodemon permet de recharger le serveur à chaque modification de notre code.

Afin de ne pas répéter les concepts que nous avons couvert dans les articles précédent, nous allons commencer avec le même code que nous avions à la fin du dernier article

Créer un dossier controllers et créer un fichier products.js avec le code suivant

const products = require('../data.js')

const getProducts = ((req, res) => {
    res.json(products)
})

const getProduct = ((req, res) => {
    const id = Number(req.params.productID)
    const product = products.find(product => product.id === id)

        if (!product) {
        return res.status(404).send('Product not found')
    }
    res.json(product)
})

const createProduct = ((req, res) => {
    const newProduct = {
        id: products.length + 1,
        name: req.body.name,
        price: req.body.price
    }
    products.push(newProduct)
    res.status(201).json(newProduct)
})

const updateProduct = ((req, res) => {
    const id = Number(req.params.productID)
    const index = products.findIndex(product => product.id === id)
    const updatedProduct = {
        id: products[index].id,
        name: req.body.name,
        price: req.body.price
    }

    products[index] = updatedProduct
    res.status(200).json('Product updated')
})

const deleteProduct = ((req, res) => {
    const id = Number(req.params.productID)
    const index = products.findIndex(product => product.id === id)
    products.splice(index,1)
    res.status(200).json('Product deleted')
})

module.exports = {
    getProducts,
    getProduct,
    createProduct,
    updateProduct,
    deleteProduct
}
Enter fullscreen mode Exit fullscreen mode

Ensuite, créer un dossier "routes" et créer le fichier products.js

const express = require('express')
const router = express.Router()

const  { 
    getProducts,
    getProduct,
    createProduct,
    updateProduct,
    deleteProduct 
} = require('../controllers/products.js')

router.get('/', getProducts)

router.get('/:productID', getProduct)

router.post('/', createProduct) 

router.put('/:productID', updateProduct) 

router.delete('/:productID', deleteProduct)

module.exports = router

Enter fullscreen mode Exit fullscreen mode

Enfin, créer un fichier app.js avec le code suivant

const express = require('express')
const app = express()
const products_routes = require('./routes/products.js')

app.listen(5000, () => {
    console.log('server is listening on port 5000')
})

app.use(express.json())
app.use('/api/products', products_routes)
Enter fullscreen mode Exit fullscreen mode

Jusqu'ici rien de nouveau, nous somme prêt pour continuer ce code en ajoutant notre base de données MongoDB

fichier .env

Pour connecter à notre base de donnée MongoDB nous avons besoins du URL de connection. MongoDB va nous fournir ce URL. Le truc c'est que pour des raisons de sécurité évidente, nous ne pouvons pas utiliser ce URL de connection directement dans notre code.

Le URL de connection dois être placé dans un fichier qui sera hors d'atteinte des utilisateurs lors du déploiement.

Pour ce faire nous allons donc créer un fichier qui contiendra notre URL de connection. Par convention ce fichier de nomme ".env" (dot env)

Vous pouvez créer ce fichier à la racine du projet et inclure le URL de connection MongoDB

// .env 
MONGO_URI = 'mongodb+srv://<username>:<password>@nodeexpress.my1j7.mongodb.net/myFirstDatabase?retryWrites=true&w=majority'
Enter fullscreen mode Exit fullscreen mode

Pour obtenir votre URL de connection de MongoDB. Connectez-vous à votre compte MongoDB cloud et à partir du menu "Databases" cliquer sur "Connect", ensuite choisir l'option "Connect you application"
Image description

MongoDB va vous afficher votre connection string, copiez là et collez là dans votre fichier .env

Dans la connection string, remplacer et avec votre nom d'utilisateur et mot de passe utilisateur cloud MongoDB et également remplacer "myFirstDatabase" avec le nom de votre base de données (soit "demo")

Communiquer avec MongoDB à partir de NodeJS

Il existe plusieurs façon de communiquer avec votre base de donnée MongoDB. Pour ce projet j'ai décidé d'utiliser le package NodeJS nommé "mongoose"

Ce packages permet facilement le lier MongoDB et votre API.

ODM

mongoose est un ODM (Object Document Mapping) ce qui signifie que mongoose permet de créer un object (appelé modèle) pour représenter et manipuler chacune de nos collections.

Cet object (model) contiendra plusieurs fonctions pré-définit qui permettront de manipuler facilement la collection associé à cet objet.

Une fois le modèle créé, pas besoin de manipuler la base de donnée, simplement utiliser les méthodes de l'object modèle et lui se chargera de communiquer à la base de donnée. Du coup, ce pattern permet d'augmenter de façon significative la facilité de manipuler la base de donnée.

Voici un exemple rapide afin visualiser le concept

const products = await Product.find({})
Enter fullscreen mode Exit fullscreen mode

Dans ce code, l'objet/model "Product" utilise la méthode "find" afin de lire tous les documents de la collection. Les documents récupérer sont envoyé dans la variables "products".

Creation d'un modèle mongoose

Nous allons maintenant créer un object/model "Product"

La première étape est d'installer le package mongoose

npm install mongoose
npm install dotenv
Enter fullscreen mode Exit fullscreen mode

Tant qu'a y être nous allons également installer le package dotenv. Ce package permet de lire le fichier de config ".env" que nous avons créer plus tôt et de charger ses variables dans le processus en cours.

Une fois le package utilisé, nous pouvons créer notre premier modèle mongoose.

Créer un dossier "models" et créer le fichier Product.js

const mongoose = require('mongoose')

const ProductSchema = new mongoose.Schema({
    name:String,
    price: Float,
})

const Product = mongoose.model('Product', ProductSchema)

module.exports = Product
Enter fullscreen mode Exit fullscreen mode

Les modèles mongoose sont créer à partir des schémas.

Le schéma permet de définir la structure d'un document. (Un peu comme les colonnes d'une table dans une base de données SQL).

Dans le dernier exemple nous définissons le schema Product qui sera la structure des documents de la collection Products

L'avant dernière ligne permet de créer le model Product à partir du schema

const Product = mongoose.model('Product', ProductSchema)
Enter fullscreen mode Exit fullscreen mode

Connection à la base de données

Maintenant que nous avons un modèle mongoose pour travailler, il faut maintenant établir la connection entre mongoose et notre base de donnée MongoDB.

Modifier le fichier app.js afin d'inclure le code de connection à la base de donnée.

const express = require('express')
const mongoose = require('mongoose')
const app = express()
const products = require('./data.js')
const products_routes = require('./routes/products.js')

require('dotenv').config()

mongoose.connect(process.env.MONGO_URI)
    .then((result) => app.listen(5000))
    .catch((err) => console.log(Error))

app.use(express.json())
app.use('/api/products', products_routes)
Enter fullscreen mode Exit fullscreen mode

Reprenons le code avec quelques explications:

Envoi le contenu du fichier .env dans l'object process.env

require('dotenv').config()
Enter fullscreen mode Exit fullscreen mode

Utilise le MONGO_URL pour créer un connection avec votre base de donnée

mongoose.connect(process.env.MONGO_URI)
Enter fullscreen mode Exit fullscreen mode

Si la connection est réussit alors lancer le serveur NodeJS sinon afficher l'erreur.

mongoose.connect(process.env.MONGO_URI)
    .then((result) => app.listen(5000))
    .catch((err) => console.log(Error))
Enter fullscreen mode Exit fullscreen mode

CRUD API

Maintenant que nous avons notre connection à MongoDB, nous pouvons modifier notre fichier "products" controller (/controllers/products.js) et y ajouter les méthodes du model Produit.

En faite le fonctionnement de ces méthodes est tellement simple et explicite que nous n'avon pas besoin de les expliquer.

const Product = require('../models/Product.js')

const getProducts = ((req, res) => {
    Product.find({})
        .then(result => res.status(200).json({ result }))
        .catch(error => res.status(500).json({msg: error}))
})

const getProduct = ((req, res) => {
    Product.findOne({ _id: req.params.productID })
        .then(result => res.status(200).json({ result }))
        .catch(() => res.status(404).json({msg: 'Product not found'}))
})

const createProduct = ((req, res) => {
    Product.create(req.body)
        .then(result => res.status(200).json({ result }))
        .catch((error) => res.status(500).json({msg:  error }))
})

const updateProduct = ((req, res) => {
    Product.findOneAndUpdate({ _id: req.params.productID }, req.body, { new: true, runValidators: true })
        .then(result => res.status(200).json({ result }))
        .catch((error) => res.status(404).json({msg: 'Product not found' }))
})

const deleteProduct = ((req, res) => {
    Product.findOneAndDelete({ _id: req.params.productID })
        .then(result => res.status(200).json({ result }))
        .catch((error) => res.status(404).json({msg: 'Product not found' }))
})

module.exports = {
    getProducts,
    getProduct,
    createProduct,
    updateProduct,
    deleteProduct
}
Enter fullscreen mode Exit fullscreen mode

Toutefois, si vous désirez connaitre en détail le fonctionnement de ces méthodes et les autres méthodes disponibles, consultez la documentation de mongoose ici : https://mongoosejs.com/docs/models.html

Tester votre API

Vous pouvez maintenant lancer le serveur Node.JS et tester l'API

$ npx nodemon app.js
Enter fullscreen mode Exit fullscreen mode

Le serveur sera lancé sur le port 5000 accessible au localhost:5000

À l'aide d'un logiciel comme Postman, vous pouvez maintenant tester votre API avec les requêtes suivantes :

GET localhost:5000/api/products

GET localhost:5000/api/product/<id>

POST localhost:5000/api/products 

PATCH localhost:5000/api/products/<id> 

DELETE localhost:5000/api/products/<id>
Enter fullscreen mode Exit fullscreen mode

À noter que pour les actions POST et PATH, vous devez les envoyer avec du contenu dans la section body de votre requête. Voici un exemple de contenu en JSON :

{
    "name": "iPhone12",
    "price": 899
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

C'est tout pour aujourd'hui, suivez moi sur twitter : https://twitter.com/EricLeCodeur afin d'être avisé de la parution du prochain article (d'ici deux jours).

Discussion (0)