TD3 : Une API "express" pour la BBI !
1. Introduction : Les contrôleurs
Dans ce TD, l'objectif sera de lier les URL d'une API "express" aux fonctions de service que vous avez développées dans le TD2.
Dans une architecture RCS (Router - Controller - Service), cette partie correspond au contrôleur. Il est responsable de la gestion des requêtes entrantes, de l'extraction des paramètres nécessaires, pour enfin, appeler les services appropriés et traiter la demande. Une fois les données récupérées, le contrôleur les renvoie au client ou retourne un code d'erreur si nécessaire.
2. Mise en place
Installez la bibliothèque javascript "express" : npm install express.
Nous aurons également besoin de la bibliothèque "cors" : npm install cors
Créez un dossier controllers/ à la racine de votre projet. Dans ce dossier, créez les fichiers : planet_controller.js, plant_controller.js et scientist_controller.js qui contiendront les fonctions permettant de traiter les requètes liés aux tables planets, plants et scientists.
Exemple de fonction de contrôleur pour la récupération de la liste des planètes
let planet_service = require("../services/planet_service");
async function get_planets(req, res){
try {
let planets = await planet_service.get_planets();
res.status(200).json({data: planets});
} catch (err) {
console.error(err);
res.status(500).json({error: err.message, data: []});
}
}
module.exports = {
get_planets,
};
Remarquez que la réponse est envoyée au format JSON avec le code HTTP 200 en cas de succès. Le corps de la réponse est toujours formulé de la même manière avec un champ data contenant les données demandées. En cas d'erreur, un champ error est ajouté au corps de la réponse avec un message d'erreur approprié. Ce message d'erreur est très important pour le débogage et la compréhension des erreurs côté client. Le code d'erreur HTTP est à définir en fonction de l'erreur rencontrée:
- 400 : Bad Request (paramètres manquants ou invalides)
- 401 : Unauthorized (non authentifié)
- 404 : Not Found (ressource non trouvée)
- 500 : Internal Server Error (erreur serveur)
Les paramètes de la requête sont accessibles via :
- req.params : pour les paramètres d'URL (ex : /planets/:id).
- req.query : pour les paramètres de requête GET (ex : /planets?sort_by=name).
- req.body : pour les corps des requête POST, PUT, DELETE.
Enfin, créez un fichier express.js à la racine de votre projet. Ce fichier sera le routeur de notre API "express".
const express = require("express")
var cors = require('cors')
const app = express()
app.use(cors())
const PORT = 3210
const router = express.Router()
const plant_controller = require("./controllers/plant_controller")
const scientist_controller = require("./controllers/scientist_controller")
const planet_controller = require("./controllers/planet_controller")
var bodyParser = require("body-parser")
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
router.get("/planets", planet_controller.get_planets)
// Exemples pour les requêtes POST, PUT, DELETE
// router.post("/exemple/requete/post", exemple_controller.fonction_post)
// router.put("/exemple/requete/put", exemple_controller.fonction_put)
// router.delete("/exemple/requete/delete", exemple_controller.fonction_delete)
app.use(router)
app.listen(PORT, function (err){
if (err) console.log(err);
console.log("Server is listening on port: "+PORT);
})
Vous pouvez lancer le serveur "express" avec la commande : node express.js. L'API sera accessible à l'adresse http://localhost:3210/.
Pour tester vos routes, vous pouvez utiliser des outils comme Postman ou curl. Mais verfifiez bien que toutes les possibilités d'erreurs soit couverte avec l'aide de l'interface client fournie ici : https://home.pirotech.fr/sqlAndProg/client/home.html
3. À vous de jouer !
Implémentez les fonctions des contrôleurs pour répondre aux besoins suivants :
Vous utiliserez les fonctions de service développées dans le TD2 pour interagir avec la base de données.
Q1 - Retourner la liste des planètes du laboratoire.
- GET : /planets
-
Format réponse :
"data":[ { "planet_id": ..., "name": ..., "galaxy": ..., "atmosphere_type": ... "temperature": ... }, ... ]
Q2 - Récupérer les informations d’un scientifique à partir de son identifiant.
- GET : /scientist
- Paramètres :
- id (obligatoire) : identifiant du scientifique.
- Format réponse :
"data": { "user_id": ..., "username": ..., "email": ..., "authorization_level": ... } - En cas d'échec émettre une erreur appropriée.
Q3 - Récupérer les informations d’une planète à partir de son identifiant.
- GET : /planet/:id
- Paramètres :
- id (obligatoire) : identifiant de la planète.
- Format réponse :
"data": { "planet_id": ..., "name": ..., "galaxy": ..., "atmosphere_type": ..., "temperature": ... } - En cas d'échec émettre une erreur appropriée.
Q4 - Lister les plantes du laboratoire.
- GET : /plants
-
Format réponse :
"data":[ { "plant_id": ..., "latin_name": ..., "common_name": ..., "is_toxic": ..., "authorization_level": ..., "planet_id": ..., "planet_name": ... }, ... ]
Q5 - Lister les plantes étudiées par un scientifique donné.
- GET : /scientist-plants
- Paramètres :
- id (obligatoire) : identifiant du scientifique.
-
Format réponse :
"data":[ { "plant_id": ..., "latin_name": ..., "common_name": ..., "is_toxic": ..., "authorization_level": ... }, ... ] - En cas d'échec émettre une erreur appropriée.
UPDATE :
Q6 - Mettre à jour le niveau du scientifique.
- PUT : /scientist
- Body :
- id (obligatoire) : identifiant du scientifique.
- authorization_level (obligatoire) : nouveau niveau d’autorisation du scientifique.
- Format réponse :
"data": { "message": "Scientist authorization level updated successfully" } - En cas d'échec émettre une erreur appropriée.
INSERT :
Q7 - Ajouter une nouvelle plante dans la base de données.
- POST : /plant
- Body :
- latin_name (obligatoire) : nom latin de la plante.
- common_name (optionnel) : nom commun de la plante.
- is_toxic (optionnel) : indique si la plante est toxique (true ou false).
- authorization_level (obligatoire) : niveau d’autorisation requis pour étudier la plante.
- planet_id (optionnel) : identifiant de la planète d’origine de la plante.
- Les champs optionnels peuvent être omis, null, undefined ou une chaîne vide.
- Format réponse :
"data": { "plant_id": ... "message": "Plant added successfully" } - En cas d'échec émettre une erreur appropriée.
DELETE :
Q8 - Suppression d’une plante à partir de son identifiant.
- DELETE : /plant
- Body :
- id (obligatoire) : identifiant de la plante à supprimer.
- Format réponse :
"data": { "message": "Plant deleted successfully" } - En cas d'échec émettre une erreur appropriée.
REQUÊTES AVANCÉES :
Q9 - Modifier la requête Q4 pour trier les plantes.
- GET : /plants
- Paramètres optionnels :
- sort_by : peut prendre les valeurs plant_id, latin_name, common_name, is_toxic ou authorization_level.
- sort_way : peut prendre les valeurs ASC ou DESC.
- Rappel :
- Les plantes avec des caractéristiques nulles doivent toujours être listées en dernier, quel que soit le sens du tri.
- Les plantes avec des caractéristiques identiques doivent être triées par identifiant croissant.
Q10 - Modifier la requête Q4 pour filtrer les plantes. Ajoutez les paramètres optionnels suivants :
-
GET : /plants
- Paramètres optionnels :
- filter_name : ne lister que les plantes dont le nom latin ou le nom commun contient cette chaîne de caractères (insensible à la casse).
- filter_is_toxic : ne lister que les plantes dont le champ is_toxic correspond à cette valeur (true ou false).
- filter_min_authorization_level : ne lister que les plantes dont le champ authorization_level est supérieur ou égal à cette valeur.
- filter_max_authorization_level : ne lister que les plantes dont le champ authorization_level est inférieur ou égal à cette valeur.
Q11 - Éditer les informations d’une plante à partir de son identifiant.
- PUT : /plant
- Body :
- id (obligatoire) : identifiant de la plante.
- latin_name (optionnel) : nom latin de la plante.
- common_name (optionnel) : nom commun de la plante.
- is_toxic (optionnel) : indique si la plante est toxique (true ou false).
- authorization_level (optionnel) : niveau d’autorisation requis pour étudier la plante.
- planet_id (optionnel) : identifiant de la planète d’origine de la plante.
- Rappel :
- Renseigner au moins un des paramètres optionnels
- Ne pas modifier les champs non fournis.
- Si l’une des propriétés de la plante vaut null, il faut définir la propriété à null sauf si une contrainte l’interdit.
- Réponse :
"data": { "message": "Plant updated successfully" } - En cas d'échec émettre une erreur appropriée.
Q12 - Permettez à un scientifique d’étudier une nouvelle plante.
- POST : /scientist-plant
- Body :
- scientist_id (obligatoire) : identifiant du scientifique.
- plant_id (obligatoire) : identifiant de la plante.
- Réponse :
"data": { "message": "Scientist-Plant association added successfully" } - En cas d'échec émettre une erreur appropriée.
Q13 - Permettez à un scientifique d’arrêter d’étudier une plante.
- DELETE : /scientist-plant
- Body :
- scientist_id (obligatoire) : identifiant du scientifique.
- plant_id (obligatoire) : identifiant de la plante.
- Réponse :
"data": { "message": "Scientist-Plant association deleted successfully" } - En cas d'échec émettre une erreur appropriée.
Q14 - Listez tous les scientifiques qui étudient des plantes avec un niveau d’autorisation supérieur au leur.
- GET : /invalid-studies
-
Format réponse :
"data":[ // Liste des scientifiques { "user_id": ..., "username": ..., "authorization_level": ..., "plants_studied":[ // Liste des plantes interdites étudiées par le scientifique { "plant_id": ..., "latin_name": ..., "common_name": ..., "authorization_level": ... }, ... ] }, ... ]
- Préparation Q15 - Q16 : VOIR TD2
Q15 - Authentification d’un scientifique.
- POST : /login
- Body :
- login : Contient soit l’id, le username ou l’email du scientifique.
- password (obligatoire) : mot de passe du scientifique.
-
Format réponse :
"data": { "authenticated": true, // ou false en cas d'échec "message": "Authentication successful" } - En cas d'échec émettre une erreur appropriée.
Q16 - Modifiez le mot de passe d’un scientifique.
- PUT : /update-password
- Body :
- login : Contient soit l’id, le username ou l’email du scientifique.
- password (obligatoire) : mot de passe actuel du scientifique.
- new_password (obligatoire) : nouveau mot de passe du scientifique.
- Rappel :
- Le nouveau mot de passe doit être différent de tous les anciens mots de passe du scientifique.
-
Format réponse :
"data": { "message": "Password updated successfully" } - En cas d'échec émettre une erreur appropriée.