Skip to main content

TP1 – Mise en pratique : Express & Prisma

Créez votre première API backend avec Express et Prisma, en appliquant une architecture propre et maintenable.


🎯 Contexte

Vous développez une API backend pour la bibliothèque de l’ULCO.

Cette API devra permettre :

  • de gérer des auteurs
  • de gérer des livres
  • d’associer un livre à un auteur

L’objectif est de manipuler une base de données relationnelle via un ORM, sans écrire de SQL, tout en respectant les bonnes pratiques vues en cours.


✅ Attendus pédagogiques

À l’issue de ce TP, vous devez être capables de :

  • mettre en place une API REST avec Express
  • utiliser Prisma comme couche d’accès aux données
  • structurer votre projet en routes / controllers / services / repositories
  • gérer les codes HTTP de manière cohérente
  • raisonner en termes de logique métier, indépendamment du framework

👉 Vous êtes guidés sur la structure, mais pas sur les implémentations détaillées : à vous de mobiliser vos compétences.


🚀 Initialisation du projet

1️⃣ Création du projet

  • Créez un nouveau dossier :
TP1_NOM_PRENOM_TPX
  • Initialisez un projet Node.js :
npm init -y

2️⃣ Dépendances à installer

Installez les dépendances nécessaires au projet :

  • express → serveur HTTP
  • prisma → ORM
  • typescript (tsc) → typage statique
  • nodemon → rechargement automatique du serveur
  • sqlite → base de données (recommandée pour ce TP)

💡 Astuce : distinguez dépendances et dépendances de développement.


3️⃣ Initialisation de Prisma

  • Initialisez Prisma :
npx prisma init

Vous devez obtenir :

  • un dossier prisma/

  • un fichier schema.prisma

  • Configurez la datasource (SQLite recommandée).

⚠️ Pensez à générer le client Prisma après chaque modification du schéma.


4️⃣ Serveur Express

  • Créez un serveur Express minimal
  • Activez le parsing JSON
  • Écoutez sur un port configurable

💡 Indice : votre serveur ne doit contenir aucune logique métier.


👤 Création du modèle Auteur

Dans schema.prisma, créez un modèle Auteur avec :

  • id : clé primaire auto-incrémentée
  • nom : String
  • prenom : String
  • anneeNaissance : Number

📌 Réfléchissez dès maintenant à :

  • l’unicité logique d’un auteur
  • la future relation avec les livres

🧩 Architecture Auteur

Pour la gestion des auteurs, vous devez respecter strictement l’architecture suivante :

auteur.route.ts        → définition des routes

auteur.controller.ts → gestion HTTP (req / res / status)

auteur.service.ts → logique métier

auteur.repository.ts → accès Prisma uniquement

💡 Règle d’or :

  • une couche n’appelle que la couche située juste en dessous
  • Prisma n’est jamais utilisé ailleurs que dans le repository

🌐 Routes Auteur à implémenter

MéthodeURLDescription
GET/authorsRécupérer tous les auteurs
GET/authors/:idRécupérer un auteur par id
POST/authorsCréer un auteur
DELETE/authors/:idSupprimer un auteur

Cas à gérer obligatoirement

  • ❌ Aucun auteur trouvé → 404 Not Found
  • ❌ Auteur déjà existant (nom, prénom, année identiques) → 409 Conflict

📌 Indice important :

La vérification des doublons doit être faite dans le service, jamais dans la route.


📚 Création du modèle Livre (niveau intermédiaire)

Ajoutez un modèle Livre avec :

  • id : clé primaire auto-incrémentée
  • titre : String
  • authorId : clé étrangère
  • relation avec Auteur

⚠️ Rappel relationnel :

  • un livre → un seul auteur
  • un auteur → plusieurs livres

💡 Vérifiez que votre schéma reflète correctement cette cardinalité.


🌐 Routes Livre à implémenter

MéthodeURLDescription
GET/booksRécupérer tous les livres
GET/books/:idRécupérer un livre
POST/booksCréer un livre
DELETE/books/:idSupprimer un livre

📌 Réfléchissez à :

  • la validation de l’auteur lors de la création d’un livre
  • la cohérence des réponses HTTP

⭐ Pour aller plus loin

Implémentez la route suivante :

GET /authors/:id/books

Elle doit retourner un auteur avec la liste de ses livres.

Exemple de réponse attendue

{
"id": 1,
"nom": "Hugo",
"prenom": "Victor",
"livres": [
{ "id": 1, "titre": "Les Misérables" },
{ "id": 2, "titre": "Notre-Dame de Paris" }
]
}

💡 Indice : cette fonctionnalité se gère principalement au niveau du repository.


🔐 Authentification (extension du TP)

Cette partie correspond au cours suivant et vise à enrichir votre API avec un système d’authentification JWT.

L’objectif n’est pas de tout réécrire, mais d’intégrer l’authentification dans l’architecture existante, en respectant les mêmes règles (routes / controllers / services / repositories).


🎯 Objectifs pédagogiques

À l’issue de cette extension, vous devez être capables de :

  • comprendre le fonctionnement global d’une authentification par JWT
  • stocker des mots de passe hashés en base de données
  • générer un token lors du login
  • protéger certaines routes avec un middleware
  • exploiter les informations du token côté backend

👤 Modèle User

Ajoutez un nouveau modèle User dans votre schéma Prisma.

Il devra contenir :

  • un id (clé primaire auto-incrémentée)
  • un name
  • un email unique
  • un password (hashé)

📌 Rappel fondamental :

Les mots de passe ne doivent JAMAIS être stockés en clair.

Vous devrez :

  • créer une migration
  • vérifier que Prisma génère bien le client

🔑 Principes de l’authentification JWT

  • Lorsqu’un utilisateur se connecte, il fournit email + mot de passe

  • Le serveur vérifie :

    1. que l’utilisateur existe
    2. que le mot de passe est correct (via bcrypt.compare)
  • Si tout est valide, le serveur génère un JWT

  • Ce token est renvoyé au client

  • Pour accéder à des routes protégées, le client doit fournir ce token dans l’en-tête :

Authorization: Bearer <TOKEN>

🧩 Architecture Auth

Vous devez respecter la même logique que pour les autres modules :

auth.route.ts        → endpoints d’authentification
auth.controller.ts → gestion HTTP
auth.service.ts → logique de login
auth.repository.ts → accès Prisma (User)
auth.middleware.ts → vérification du JWT

⚠️ Le middleware ne contient aucune logique métier, uniquement de la validation de token.


🌐 Endpoint à implémenter

POST /auth/login

Cette route doit :

  1. recevoir un email et un password
  2. vérifier que l’utilisateur existe
  3. vérifier le mot de passe
  4. générer un JWT signé avec une clé secrète
  5. renvoyer le token et les informations publiques de l’utilisateur

📌 Codes HTTP attendus :

  • 200 → connexion réussie
  • 401 → identifiants invalides
  • 500 → erreur serveur

🛡️ Middleware d’authentification

Créez un middleware chargé de :

  • récupérer le token depuis l’en-tête Authorization
  • vérifier sa validité
  • extraire les informations utiles (ex: userId)
  • bloquer l’accès si le token est manquant, invalide ou expiré

📌 Indice :

Vous devrez étendre le type Request d’Express pour y attacher l’identifiant utilisateur.


🔒 Protéger certaines routes

Appliquez le middleware d’authentification sur :

  • au moins une route existante (par exemple la création d’un utilisateur ou d’une ressource)

Exemple de réflexion attendue :

  • Quelles routes doivent être publiques ?
  • Quelles routes doivent être réservées aux utilisateurs authentifiés ?

⭐ Pour aller plus loin (optionnel)

  • Ajouter une durée d’expiration au token
  • Centraliser la gestion des erreurs d’authentification
  • Associer certaines actions à l’utilisateur connecté

🏁 Fin du TP

Lorsque vous avez terminé :

  • assurez-vous que votre projet est fonctionnel et proprement structuré
  • testez vos routes (Postman, Insomnia, etc.)

📣 Contactez-moi pour validation.

👉 Un bonus pourra être accordé sur le projet final en fonction :

  • de la qualité de l’architecture
  • de la rigueur du code
  • de la gestion des erreurs

Bon courage 🚀