• Contenu
  • Bas de page
logo ouidoulogo ouidoulogo ouidoulogo ouidou
  • Qui sommes-nous ?
  • Offres
    • 💻 Applications métier
    • 🤝 Collaboration des équipes
    • 🛡️ Sécurisation et optimisation du système d’information
    • 🔗 Transformation numérique
  • Expertises
    • 🖥️ Développement logiciel
    • ♾️ DevSecOps
    • ⚙️ Intégration de logiciels et négoce de licences
      • Atlassian : Jira, Confluence, Bitbucket…
      • Plateforme monday.com
      • GitLab
      • SonarQube
    • 📚​ Logiciel de CRM et de gestion
    • 🎨 UX/UI design
    • 🌐 Accessibilité Numérique
    • 🗂️​ Démarches simplifiées
    • 📝 Formations Atlassian
  • Références
  • Carrières
    • 🧐 Pourquoi rejoindre Ouidou ?
    • ✍🏻 Nous rejoindre
    • 👨‍💻 Rencontrer nos collaborateurs
    • 🚀 Grandir chez Ouidou
  • RSE
  • Ressources
    • 🗞️ Actualités
    • 🔍 Articles techniques
    • 📖 Livres blancs
    • 🎙️ Interviews Clients
Nous contacter
✕
Très belle année 2024
Très belle année 2024
5 janvier 2024
Comment Ouidou accompagne Innovative Digital Technologies dans la mise à disposition de Mes Démarches ? 
Comment Ouidou accompagne Innovative Digital Technologies dans la mise à disposition de Mes Démarches ? 
15 janvier 2024
Ressources > Articles techniques > Monter une API avec Node.js et MongoDB

Monter une API avec Node.js et MongoDB

Article écrit par Jordan

Ce tutoriel a pour objectif l’installation et l’utilisation de Node.js et de MongoDB par le biais d’un petit projet web. Node.js est une plateforme logicielle libre et événementielle en JavaScript orientée vers les applications réseau qui doivent pouvoir monter en charge. MongoDB est un SGBD (système de gestion de base de données) orienté documents, ne nécessitant pas de schéma prédéfini des données.

À la fin de ce tutoriel, vous serez capable de monter une API à l’aide de Node.js et de MongoDB !

Installation

Node.js

Pour installer Node.js, rendez-vous sur le site officiel et téléchargez Node.js et npm. Vérifiez l’installation avec les commandes suivantes dans le terminal :

$ node -v
$ npm -v

MongoDB

Pour installer MongoDB, rendez-vous sur le site officiel et téléchargez la version adaptée à votre système d’exploitation. Suivez les étapes pour modifier le fichier bash (.bashrc / .bash_profile) et ajouter le chemin du fichier téléchargé. Ensuite, créez un dossier pour la base de données et lancez le serveur MongoDB :

$ sudo mkdir -p /data/db
$ sudo chown -R id -un /data/db

Vous pouvez maintenant lancer votre serveur MongoDB avec la commande suivante.

$ mongod

Si vous souhaitez accéder à votre base de données en ligne de commande, il vous suffit d’ouvrir un autre terminal et de lancer la commande suivante.

$ mongo

Pour la suite de notre projet, il vous faut créer une base de données que vous nommerez amazon et dans laquelle vous stockerez vos livres.

> use amazon
> db.books.insert({title:"Harry Potter", author:"J.K.Rowling"})

Configuration

Création du projet

Utilisez Express Generator pour créer le squelette de l’application.

$ npm install express-generator -g

Une fois Express installé, vous allez générer le squelette de notre projet.

$ express bookServer

Mongoose

Vous allez installer Mongoose pour la suite du projet. Ce dernier est un framework permettant de faciliter la connexion entre MongoDB et Express.

$ npm install mongoose --save

Dans le fichier app.js, ajoutez :

var mongoose = require('mongoose');
var config = require('mongodb://localhost:27017/amazon')

const connect = mongoose.connect(config, { useNewUrlParser: true });
connect.then(
  db => {
    console.log("Connected correctly to the server");
  },
  err => {
    console.log(err);
  }
);

Routes

Définissez les routes dans app.js :

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users.routes');
var booksRouter = require('./routes/books.routes');

Il faut à présent définir ces différentes routes. Rendez-vous dans le dossier routes et créez un fichier nommé books.routes.js dans lequel vous rentrerez les lignes suivantes.

const controller = require('../controllers/books.controller');
const express = require('express');

const router = express.Router();

router.use(express.json());
router
  .route('/')
  .get(controller.getAll)
  .post(controller.addOne);

router
  .route('/:bookId')
  .get(controller.getOne)
  .put(controller.updateOne)
  .delete(controller.deleteOne);

module.exports = router;

Controller

À la racine de votre projet, vous allez créer un dossier controllers dans lequel vous allez créer un fichier books.controller.js. Ce fichier comportera toutes vos méthodes en lien avec les books.

const Books = require("../models/books.model");

const controller = {
  getAll: (req, res, next) => {
    Books.find({})
      .then(
        books => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(books);
        },
        err => next(err)
      )
      .catch(err => next(err));
  },
  addOne: (req, res, next) => {
    Books.create(req.body)
      .then(
        book => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(book);
        },
        err => next(err)
      )
      .catch(err => next(err));
  },
  getOne: (req, res, next) => {
    Books.findById(req.params.bookId)
      .then(
        book => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(book);
        },
        err => next(err)
      )
      .catch(err => next(err));
  },
  updateOne: (req, res, next) => {
    Books.findByIdAndUpdate(req.params.bookId, { $set: req.body }, { new: true })
      .then(
        book => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(book);
        },
        err => next(err)
      )
      .catch(err => next(err));
  },
  deleteOne: (req, res, next) => {
    Books.findByIdAndRemove(req.params.bookId)
      .then((resp) => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(resp);
        },
        err => next(err)
      )
      .catch(err => next(err));
  }
};

module.exports = controller;

Models

Vous allez créer les différents modèles de votre application. Commencez par créer un dossier modèles à la racine de votre projet. Dans ce dossier, créez à présent un fichier books.models.js. Ces modèles feront le mapping entre votre base de données et votre API.

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
require('mongoose-currency').loadType(mongoose);
const Currency = mongoose.Types.Currency;

const commentSchema = new Schema({
  rating: { type: Number, min: 1, max: 5, required: true },
  comment: { type: String, required: true },
  author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
}, { timestamps: true });

const bookSchema = new Schema({
  title: { type: String, required: true },
  author: { type: String, required: true },
  image: { type: String },
  year: { type: Number },
  price: { type: Currency },
  description: { type: String, required: true },
  bestseller: { type: Boolean, default: false },
  comments: [commentSchema]
}, { timestamps: true });

const Books = mongoose.model('Book', bookSchema);
module.exports = Books;

Vous venez d’utiliser le type de monnaie de mongoose, il faut donc veiller à l’installer auparavant. Rendez-vous dans votre terminal et tapez y la commande suivante.

$ npm install mongoose-currency --save

Lancement

Vous avez maintenant la base du projet, vous pouvez le tester en tapant la commande suivante.

$ npm start

Rendez-vous sur votre navigateur ou sur Postman à l’adresse suivante pour pouvoir tester votre application : http://localhost:3000/books/

PassportJS

Vous allez maintenant rendre votre application un peu plus sûre, pour cela, vous allez créer des utilisateurs. À la création d’un utilisateur un token sera généré et c’est uniquement grâce à ce dernier que vous pourrez avoir accès aux modifications de la base de données. Avant de commencer, veuillez installer les dépendances nécessaires.

$ npm install mongoose bcrypt-nodejs jsonwebtoken morgan passport passport-jwt --save

Commencez par créer un user. Pour ce faire, créer un dossier config à la racine de votre projet. Dans ce dossier, créez y un premier fichier nommé database.js dans lequel vous allez ajouter les lignes suivantes.

module.exports = {
  'secret': 'nodeauthsecret',
  'database': 'mongodb://localhost:27017/amazon'
};

Dans le second fichier, que vous appellerez passport.js, vous allez ajouter les lignes suivantes.

var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;

var User = require('../models/users.model');
var config = require('../config/database');

module.exports = function (passport) {
  var opts = {};
  opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("jwt");
  opts.secretOrKey = config.secret;
  passport.use(new JwtStrategy(opts, function (jwt_payload, done) {
    User.findOne({ id: jwt_payload.id }, function (err, user) {
      if (err) {
        return done(err, false);
      }
      if (user) {
        done(null, user);
      } else {
        done(null, false);
      }
    });
  }));
};

Comme vous avez pu le constater, vous avez appelé le model User, vous allez donc le créer. Dans le dossier models, créez un fichier users.model.js dans lequel vous allez définir le schéma de votre user.

var bcrypt = require('bcrypt-nodejs');
const mongoose = require("mongoose");
const Schema = mongoose.Schema;

var userSchema = new Schema({
  firstName: { type: String },
  lastName: { type: String },
  username: { type: String, unique: true, required: true },
  password: { type: String, required: true }
}, { timestamps: true });

userSchema.pre('save', function (next) {
  var user = this;
  if (this.isModified('password') || this.isNew) {
    bcrypt.genSalt(10, function (err, salt) {
      if (err) {
        return next(err);
      }
      bcrypt.hash(user.password, salt, null, function (err, hash) {
        if (err) {
          return next(err);
        }
        user.password = hash;
        next();
      });
    });
  } else {
    return next();
  }
});

userSchema.methods.comparePassword = function (passw, cb) {
  bcrypt.compare(passw, this.password, function (err, isMatch) {
    if (err) {
      return cb(err);
    }
    cb(null, isMatch);
  });
};

const User = mongoose.model('User', userSchema);
module.exports = User;

Une fois le modèle créé, il faut créer les différentes routes. Vous aurez deux routes : une première permettant la création d’un utilisateur et une seconde permettant l’authentification et la connexion. Dans le dossier routes, créez un fichier users.routes.js et ajoutez les différentes routes.

var express = require('express');
var router = express.Router();

var mongoose = require('mongoose');
var passport = require('passport');
var config = require('../config/database');
require('../config/passport')(passport);
var jwt = require('jsonwebtoken');
var User = require("../models/users.model");


router.get('/', function (req, res, next) {
  res.send('respond with a resource');
});

router.post('/enregistrement', function (req, res) {
  if (!req.body.username || !req.body.password) {
    res.json({ success: false, msg: 'Veuillez renseigner le username et le mot de passe.' });
  } else {
    var newUser = new User({
      username: req.body.username,
      password: req.body.password
    });
    newUser.save(function (err) {
      if (err) {
        return res.json({ success: false, msg: 'Ce username existe deja.' });
      }
      res.json({ success: true, msg: 'Succes. Nouvel utilisateur créé.' });
    });
  }
});

router.post('/connexion', function (req, res) {
  User.findOne({
    username: req.body.username
  }, function (err, user) {
    if (err) throw err;

    if (!user) {
      res.status(401).send({ success: false, msg: 'Authentication erronée. Utilisateur non trouvé.' });
    } else {
      user.comparePassword(req.body.password, function (err, isMatch) {
        if (isMatch && !err) {
          var token = jwt.sign(user.toJSON(), config.secret);
          res.json({ success: true, token: 'JWT ' + token });
        } else {
          res.status(401).send({ success: false, msg: 'Authentication erronée. Mauvais mot de passe.' });
        }
      });
    }
  });
});

module.exports = router;

Une fois ces fichiers créés, il suffit de renseigner dans le fichier app.js.

// ...
var config = require('./config/database');
var passport = require('passport');
// ...
app.use(passport.initialize());
// ...

Il faut à présent mettre en place cette sécurité, vous allez l’appliquer pour la modification de vos livres en base de données, c’est-à-dire pour les fonctions addOne, updateOne, et deleteOne. Rendez-vous dans le fichier books.controller.js et commencez par ajouter la fonction qui permettra de récupérer le token dans l’en-tête de l’URL. Tout en bas, ajoutez la fonction suivante.

// ...
getToken = function (headers) {
  if (headers && headers.authorization) {
    var parted = headers.authorization.split(' ');
    if (parted.length === 2) {
      return parted[1];
    } else {
      return null;
    }
  } else {
    return null;
  }
};

À présent dans les 3 fonctions citées précédemment, encadrer vos corps d’une vérification du token à l’aide d’un simple if/else.

deleteOne: (req, res, next) => {
  var token = getToken(req.headers);
  if (token) {
    // corps de la fonction
  } else {
    return res.status(403).send({ success: false, msg: 'Acces refusé' });
  }
}

Dans le fichier books.routes.js vous allez renseigner les différentes fonctions pour lesquelles passport est utilisé.

const authenticate = passport.authenticate('jwt', { session: false });
// ...
var passport = require("passport");
// ...
router.use(express.json());
router
  // ...
  .post(authenticate, controller.addOne);

router
  // ...
  .put(authenticate, controller.updateOne)
  .delete(authenticate, controller.deleteOne);

Pour utiliser Postman, il faut commencer par créer un user, pour se faire lancer un POST avec l’adresse suivante http://localhost:3000/users/enregistrement en prenant soin de renseigner le username et le password dans le body comme suit.

{
  "username": "ouidou",
  "password": "ouidou"
}

Vous devriez obtenir un résultat comme celui-ci.

{
  "success": true,
  "msg": "Succes. Nouvel utilisateur créé."
}

À présent, avec l’utilisateur créé, vous allez vous connecter à l’adresse suivante http://localhost:3000/users/connexion en renseignant dans le body le même username et password créé précédemment. Vous devriez obtenir un résultat comme suit.

{
  "success": true,
  "token": "JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzdjMGU3ZTMxMjYzZjQyZjcyOTFjMTIiLCJ1c2VybmFtZSI6ImpvaiIsInBhc3N3b3JkIjoiJDJhJDEwJFJiZ3Z5NG9EU2liVmZxUHJBRE1LTS5CMjIuRHBWWmdSZzJEQ1ZwR0NpTHRYMTgzZkJhR3hlIiwiY3JlYXRlZEF0IjoiMjAxOS0wMy0wM1QxNzoyNzoyNi4zOTZaIiwidXBkYXRlZEF0IjoiMjAxOS0wMy0wM1QxNzoyNzoyNi4zOTZaIiwiX192IjowLCJpYXQiOjE1NTE2MzQxNzN9.fzFUDem8vV6TFT1xJniTOm7KHueNyBZr3MsW9huQpuE"
}

Vous venez de générer votre token et pour vous en servir rien de plus simple. Dans les fonctions dans lesquelles vous avez utilisé passport (addOne, updateOne, et deleteOne) vous aller dans les headers de votre URL et vous allez rajouter la Key Authorization et coller la token généré.

Cors

Cors est un package Node.js destiné à fournir un middleware Connect/Express pouvant être utilisé pour activer Cors avec diverses options. Pour installer Cors, il vous suffit de taper la commande suivante :

$ npm install cors --save

Il faut ensuite spécifier à votre application l’utilisation de ce nouveau module. Pour cela, vous devez vous rendre dans votre fichier app.js et y insérer les deux lignes suivantes.

// ...
var cors = require('cors');
// ...
app.use(cors());

HTTPS

L’HyperText Transfer Protocol Secure (HTTPS, littéralement « protocole de transfert hypertexte sécurisé ») est la combinaison du HTTP avec une couche de chiffrement comme SSL ou TLS. Vous allez maintenant ajouter ce protocole dans votre application. Vous allez avoir besoin de OpenSSL, si vous ne le possédez pas, je vous invite à le télécharger à cette adresse. Ouvrez un terminal et placez vous dans votre projet.

$ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365

Il faut ensuite répondre à toutes les questions qui vous seront posées. Vous devriez voir apparaître deux nouveaux fichiers : cert.pem et key.perm.

Vous allez maintenant “créer un serveur https”. Rendez-vous dans le fichier app.js et ajoutez les lignes suivantes.

// ...

var https = require('https');
var fs = require('fs');

// ...

https.createServer({
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
}, app).listen(443);

// ...

Une fois cela effectué, vous pouvez exécuter la commande de lancement.

$ npm start

Il est possible qu’une erreur apparaisse, dans ce cas la vous devez supprimer le mot de passe avec la commande suivante.

$ openssl rsa -in key.pem -out newkey.pem

Après avoir fait cela un fichier newkey.pem devrait apparaître. Supprimer l’ancien key.pem et renommé newkey.pem en key.pem.

Vous pouvez vérifier que votre serveur https fonctionne en vous rendant a l’adresse https://localhost:443/books. Pour utiliser sur Postman, vous devez vous rendre dans les préférences de l’application, onglet Certificates et ajoutez le certificat créé au début.

Vous devez aussi vous rendre dans l’onglet Général mettez à “off” la ligne SSL certificate verification.

La dernière étape consiste à rediriger notre application vers https lorsque l’on entre dedans. Pour ce faire, vous allez utiliser un module spécifique. Commencez par télécharger express force SSL.

$ npm install express-force-ssl --save

Rendez-vous dans le fichier app.js et ajouter les lignes suivantes.

// ...
var forceSsl = require('express-force-ssl');
// ...
app.use(forceSsl);

À présen, toutes les URLs que vous utiliserez seront sur l’adresse https://localhost:443/.

Book subdocument

Vous voulez à présent mettre en place des commentaires qui seront relatifs à chaque livre, pour se faire, vous allez mettre en place une structure de commentaire.

Comme vous avez pu le constater dans le début du tutoriel, vous aviez déjà créé la structure des commentaires dans le fichier books.model.js.

Commencez par vous rendre dans le fichier books.routes.js et rajoutez les routes avec lesquelles vous accéderez aux commentaires.

// ...
const controller_comments = require('../controllers/comments.controller');
// ...
router
  .route('/:bookId/comments')
  .get(controller_comments.getAll)
  .post(authenticate, controller_comments.addOne);
router
  .route('/:bookId/comments/:commentId')
  .get(controller_comments.getOne)
  .put(authenticate, controller_comments.updateOne)
  .delete(authenticate, controller_comments.deleteOne);

Une fois les routes mises en place, vous allez créer votre controller. Dans le dossier controllers, créez un fichier comments.controller.js.

const Books = require("../models/books.model");

const controller_comments = {
  getAll: (req, res, next) => {
    Books.findById(req.params.bookId)
      .then(
        book => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(book.comments);
        },
        err => next(err)
      )
      .catch(err => next(err));
  },
  addOne: (req, res, next) => {
    var token = getToken(req.headers);
    if (token) {
      Books.findByIdAndUpdate(req.params.bookId, { $push: { comments: req.body } })
        .then(
          book => {
            res.statutCode = 200;
            res.setHeader("Content-Type", "application/json");
            res.json(book.comments);
          },
          err => next(err)
        )
        .catch(err => next(err));
    } else {
      return res.status(403).send({ success: false, msg: 'Interdit' });
    }
  },
  getOne: (req, res, next) => {
    Books.findById(req.params.bookId)
      .then(
        book => {
          res.statutCode = 200;
          res.setHeader("Content-Type", "application/json");
          res.json(book.comments.id(req.params.commentId));
        },
        err => next(err)
      )
      .catch(err => next(err));
  },
  updateOne: (req, res, next) => {
    var token = getToken(req.headers);
    if (token) {
      Books.update(
        {
          "_id": req.params.bookId,
          "comments._id": req.params.commentId
        },
        {
          $set: {
            "comments.$.rating": req.body.rating,
            "comments.$.comment": req.body.comment,
            "comments.$.author": req.body.author
          }
        },
        {
          new: true
        }
      )
        .then(
          book => {
            res.statutCode = 200;
            res.setHeader("Content-Type", "application/json");
            res.json(book);
          },
          err => next(err)
        )
        .catch(err => next(err));
    } else {
      return res.status(403).send({ success: false, msg: 'Interdit' });
    }
  },
  deleteOne: (req, res, next) => {
    var token = getToken(req.headers);
    if (token) {
      Books.findByIdAndUpdate(
        req.params.bookId,
        {
          $pull:
            {
              comments:
                {
                  "_id": req.params.commentId
                }
            }
        }
      )
        .then(
          book => {
            res.statutCode = 200;
            res.setHeader("Content-Type", "application/json");
            res.json(book);
          },
          err => next(err)
        )
        .catch(err => next(err));
    } else {
      return res.status(403).send({ success: false, msg: 'Interdit' });
    }
  }
};

Vous pouvez à présent tester à l’aide de Postman la récupération/modification des commentaires liés à chaque livre.

Et voilà ! Vous avez maintenant acquis les compétences nécessaires pour créer une API en utilisant Node.js et MongoDB. Les concepts que nous avons explorés sont souvent applicables à d’autres langages et technologies lors de la création d’API, vous donnant ainsi une petite base pour aborder d’autres projets.

À lire aussi

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique

Lire la suite

intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 

Lire la suite

Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 

Lire la suite

image miniature les nouveautés Atlassian
26 février 2025

Les nouveautés Atlassian en 2025

Lire la suite

Articles associés

Fresque numérique miniature image
16 avril 2025

Fresque du Numérique


Lire la suite
intelligence artificielle Ouicommit miniature image
17 mars 2025

Ouicommit – L’intelligence artificielle en entreprise, on y est ! 


Lire la suite
Image miniature Hackathon Women in Tech
13 mars 2025

Hackathon Women in Tech :  un engagement pour une tech plus inclusive 


Lire la suite

À propos

  • Qui sommes-nous ?
  • Références
  • RSE
  • Ressources

Offres

  • Applications métier
  • Collaboration des équipes
  • Sécurisation et optimisation du système d’information
  • Transformation numérique

Expertises

  • Développement logiciel
  • DevSecOps
  • Intégration de logiciels et négoce de licences
  • Logiciel de CRM et de gestion
  • UX/UI design
  • Accessibilité Numérique
  • Démarches simplifiées
  • Formations Atlassian

Carrières

  • Pourquoi rejoindre Ouidou ?
  • Nous rejoindre
  • Rencontrer nos collaborateurs
  • Grandir chez Ouidou

SIEGE SOCIAL
70-74 boulevard Garibaldi, 75015 Paris

Ouidou Nord
165 Avenue de Bretagne, 59000 Lille

Ouidou Rhône-Alpes
4 place Amédée Bonnet, 69002 Lyon

Ouidou Grand-Ouest
2 rue Crucy, 44000 Nantes

Ouidou Grand-Est
7 cour des Cigarières, 67000 Strasbourg

  • Linkedin Ouidou
  • GitHub Ouidou
  • Youtube Ouidou
© 2024 Ouidou | Tous droits réservés | Plan du site | Mentions légales | Déclaration d'accessibilité
    Nous contacter