🔥 Vous devez terminer le TD précédent avant de commencer celui-ci.
Vous êtes invités à créer les dossiers suivants : client src/config src/controllers src/models src/routes
Dans cette séance, nous allons utiliser un modèle de données pour notre base. Pour ce faire, nous utiliserons le pilote mongoose.
La première chose à faire est de définir le schéma des données contenues dans la base. Éditez un fichier contactModel.js dans le répertoire models contenant le texte ci-dessous :
import { Schema, model } from 'mongoose';
// Setup schema
const contactSchema = new Schema({
name: { type: String },
age: { type: Number }
});
export default model('Contact', contactSchema);
Une bonne pratique est de regrouper toutes les informations de connexion à la base au même endroit. Créez un fichier db.js dans le répertoire config qui contiendra toutes les informations pour se connecter à la base de données.
import { connect, disconnect } from 'mongoose';
import { config } from "dotenv";
config();
async function connectDB() {
try {
console.log("Opening connection");
const conn = await connect(process.env.MONGO_URI + '/' + process.env.DB_NAME, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch(err) {
disconnect();
console.error(err);
process.exit(1);
}
}
export default connectDB
Modifiez le fichier server.js de la manière suivante
import connectDb from "./config/db.js";
const app = express();
connectDb();
Nous allons définir toutes les routes de notre API dans un fichier index.js dans le dossier routes.
1) Éditez le fichier routes/index.js comme suit:
import { Router } from 'express';
const router = Router();
router.get('/', function (req, res) {
res.status(200).json({
status: 'API is Working',
message: 'Welcome!',
});
});
2) Ajoutez la ligne app.use('/api', routes); dans le fichier server.js
3) Créez un fichier rest.http dans le dossier client contenant les lignes ci-dessous
### Default URL
GET http://localhost:5000/
### Default API URL
GET http://localhost:5000/api/
1) Créez un fichier contactController dans le répertoire controllers. Nous allons implémenter les méthodes suivantes : getAllContacts, getContactById, updateContact, removeContact, addContact.
import { countDocuments, find } from '../models/contactModel.js';
// Get all contacts
export async function getAllContacts() {
let total = await countDocuments({});
let limit = parseInt(total);
try {
const contacts = await find().limit(limit);
return {
success: true,
data: contacts,
total: total.toString(),
}
} catch (err) {
return { success: false, message: "Contacts not found " + err };
}
}
// Get contact by Id
export async function getContactById(id) {
// todo
}
// Add a new contact, returns the added contact
export async function addContact(body) {
// todo
}
// Update an existing contact
export async function updateContact(id, name = null, age = null) {
// todo
}
// Remove an existing contact
export async function removeContact(id) {
// todo
}
2) Ajoutons maintenant la route correspondante dans le dossier routes.
import { getAllContacts, getContactById, updateContact, removeContact, addContact } from '../controllers/contactController.js';
router.route('/contacts').get(async (req, res) => {
let response = await getAllContacts();
if (response.success == true) {
res.status(200).json(response);
} else {
res.status(404).json(response);
}
});
3) Testez votre nouvelle route (ajoutez une requête dans le fichier rest.http)
4) Ajoutez le code nécessaire pour les routes suivantes
GET /contacts/:id (getContactById)
POST /contacts (addContact)
PUT /contacts/:id (updateContact)
DELETE /contacts/:id (removeContact)
Nous allons fournir une documentation de notre API sous la forme d’une spécification openAPI qui permet de décrire précisément les routes d’une API et comment les utiliser.
1) Ajoutez les dépendances suivantes au fichier server.js
import swaggerJsDoc from 'swagger-jsdoc';
import { serve, setup } from 'swagger-ui-express';
const options = {
definition: {
openapi: '3.0.0',
info: {
title: 'Contact REST API',
description: "A REST API built with Express and MongoDB.",
version: '0.1',
},
servers: [
{
url: 'http://localhost:5000/api',
description: 'Development server',
},
],
},
apis: ["./src/routes/*.js"],
}
const openapiSpecification = swaggerJsDoc(options);
app.use('/docs', serve, setup(openapiSpecification));
2) Il suffit maintenant d’ajouter quelques annotations dans le fichier routes/index.js de la manière suivante :
/**
* @openapi
* /contacts:
* get:
* description: All contacts
* responses:
* '200':
* description: Returns all the contacts
*/
router.route('/contacts').get(async (req, res) => { [...] }
3) Vous pouvez ensuite visualiser la documentation de l’API via l’url http://localhost:5000/docs
Dans cette dernière partie, nous allons sécuriser l’accès aux contacts en ajoutant un système d’authentification basé sur des JSON Web Tokens (JWT).
1) Installez les dépendances nécessaires : npm install jsonwebtoken bcrypt.
2) Ajoutez un modèle userModel.js dans models décrivant un utilisateur avec un email unique et un mot de passe. Préparez-le pour hacher le mot de passe avec bcrypt avant l’enregistrement, et exposez une méthode permettant de comparer un mot de passe fourni avec celui stocké.
3) Créez un authController.js dans controllers avec deux fonctions : register, qui crée un nouvel utilisateur puis renvoie son identifiant et son email, et login, qui vérifie les identifiants et génère un JWT via jsonwebtoken.
4) Ajoutez un middleware requireAuth.js dans middleware qui lit le header Authorization, extrait le token, le valide avec jsonwebtoken et renseigne req.user, ou renvoie une erreur 401 si le token manque ou est invalide.
5) Dans routes/index.js, exposez deux routes publiques POST /auth/register et POST /auth/login utilisant le contrôleur précédemment créé, puis appliquez requireAuth aux routes contacts afin que toutes les opérations CRUD vérifient le token.
6) Mettez à jour le fichier client/rest.http pour inclure des exemples de requêtes d’enregistrement, de connexion et une requête protégée sur /contacts montrant comment fournir le token dans le header Authorization.
7) Complétez la documentation OpenAPI pour ajouter les nouvelles routes d’authentification et indiquer que les routes contacts requièrent un header Authorization: Bearer <token>.
Vous disposez maintenant d’une API dont l’accès est contrôlé par un système d’authentification simple basé sur des JWT.