LIFWEB TP5a - Programmation Node.js avec hapi
Ce projet sur quatre séances consiste à réaliser un service de réduction d’URL comme https://bit.ly/ ou https://tinyurl.com/, et à le déployer sur un serveur de l’université. Il s’agit de réaliser :
- D’une part un serveur d’API en Node.js,
- D’autre part, un client AJAX qui propose une interface graphique sur cette API.
Introduction
🔖 Un projet de départ d’application est disponible sur le GitLab https://forge.univ-lyon1.fr/aurelien.tabard/lifweb-url-shortener-2025. 🔖
Fonctionnalités
Le backend du service transforme une URL d’origine dite URL longue, comme https://perdu.com, en une URL réduite, par exemple http://localhost/WmFJQp qui redirigera vers l’URL d’origine lors d’une visite. Le service propose les routes suivantes, qui répondent des documents JSON (en-tête Content-Type: application/json
) :
GET /
accueil ;GET /health
informations générales sur le service ;GET /api
informations sur les liens, dont le nombre total ;POST /api
création d’un lien réduit à partir d’une URL longue (donnée dans le champuri
du corps de la requête);GET /api/{short}/status
état d’un lien, dont le nombre de visites ;DELETE /api/{short}
suppression d’un lien.
La route suivante en revanche, ne répond pas de JSON, mais redirige l’utilisateur, on appelle cette action la visite du lien (court) :
GET /api/{short}
redirige le lien raccourci vers l’URL longue d’origine.
Le frontend du service est un client AJAX dans le navigateur qui permet essentiellement de créer de nouveaux liens réduits. Il s’agit d’une stratégie client-side rendering où toute la construction du HTML et du DOM est faite du côté du navigateur, le serveur ne fournissant que des données JSON.
💡 Les deux parties backend / serveur et frontend / client sont indépendantes ne bloquez pas sur la partie serveur. 💡
Installation
⚠️ Faire un fork du projet de départ (bouton « fork » depuis l’interface web GitLab) https://forge.univ-lyon1.fr/aurelien.tabard/lifweb-url-shortener-2025 dans votre compte en gardant le même nom lifweb-url-shortener-2025
. ⚠️
⚠️ Votre fork devra être privé. Donnez des droits d’accès reporter
à aurelien.tabard
et à votre chargé de TP. ⚠️
Suivre le README.md
du projet de départ pour l’installation et le premier lancement.
Une application comme SQLite Studio ou SQLite Browser vous sera utile pour explorer le contenu de votre base de données. Vous pouvez aussi utiliser la commande sqlite3 database.sqlite
en mode texte pour entrer directement des commandes SQL (c’est la seule option sur les machines de la fac).
httpie vous sera utile pour tester vos appels d’API (à installer pour utiliser les commandes http
et https
depuis un shell tournant sur le client, n’utilisez pas la version web). Sur vos machines personnelles, utiliser votre gestionnaire de paquet (sudo apt install httpie
sous Ubuntu). Sur les machines de la fac, vous n’êtes pas root mais vous pouvez faire pip install httpie
puis ajouter PATH="$HOME"/.local/bin:"$PATH"
à votre fichier ~/.bashrc
et faire exec bash
pour relancer bash.
Partie 1 : serveur
Dans cette partie, il n’y a pas encore de frontend, il s’agit uniquement du backend qui va recevoir des requêtes HTTP et répondre des contenus JSON. Il n’y a encore ni CSS, ni HTML, ni JS côté client.
Exercice 1 : prise en main
Installer httpie si ce n’est pas encore fait (cf. ci-dessus).
- Faire une première requête avec
httpie
oucurl
sur la route/health
de l’API. - Faire une seconde requête avec
httpie
pour créer un nouveau raccourci d’url (voir les routes ci-dessus). - Vérifier avec une requête à l’API que l’url a bien été ajouté.
- Vous pouvez également vérifier que la base de données a bien été modifiée avec SQLite Studio, SQLite Browser, ou en ligne de commande avec par exemple :
sqlite3 database.sqlite -column -header 'select * from links;'
Répondre aux questions de compréhension suivantes :
- Donner les différences entre
npm start
etnpm run prod
. - Quels sont les différents niveaux supportés par
server.log()
? - Comment exécuter les tests de
tests/server.test.js
?
Exercice 2 : compléter les routes existantes
Compléter les routes existantes de l’API.
- Implémenter la route
/api/{short}/status
- Retourner simplement tous les champs de la relation.
- Si le lien demandé n’existe pas, retourner un code 404.
- Ajouter la fonctionnalité qui permet de compter le nombre de fois où chaque lien est visité.
- Pour cela, incrémenter l’attribut
visit
de la base de données à chaque visite. - Pour réaliser la fonctionnalité, ajouter une fonction dans
db/index.js
et modifier le contrôleur deGET /api/{short}
pour l’utiliser.
- Pour cela, incrémenter l’attribut
- Similairement, ajouter un attribut
last_visited_at
pour garder la date de dernière visite.- Ici, il faudra modifier en plus le schéma de la base de données pour ajouter l’attribut.
- sqlite n’a pas de type date/time dédié, on stocke du
TEXT
qui pourra être toutefois manipulé avec des fonctions dédiées.
⚠️ Compléter tests/server.test.js
et tester la mise-à-jour. ⚠️
Exercice 3 : Suppression de liens
Ajouter une fonctionnalité de suppression de lien raccourci sur la route DELETE /api/{short}
On souhaite contrôler que seul le créateur d’un lien puisse le supprimer. Pour cela l’API fournit un code secret généré lors de la création du lien. Ce secret doit être communiqué lors de la requête de suppression pour que celle-ci réussisse.
- Étendre la base de données avec un nouveau champ
secret_key
; - Tirer un secret au hasard lors de la création d’un nouveau lien raccourci et l’enregistrer en base ;
- Sur la route
DELETE /api/{short}
:- Si le lien demandé n’existe pas, retourner un code 404 ;
- S’il n’y a pas d’attribut
secret_key
, retourner un code 400 ; - Si le secret ne correspond pas au lien demandé, retourner un code 401 ;
- Sinon, supprimer de la base et renvoyer un code 200 avec les détails du lien supprimé.
- Pour le traitement des cas d’erreurs précédents, adopter la stratégie fail fast, voir SO.
⚠️ Compléter tests/server.test.js
et tester la nouvelle fonctionnalité. ⚠️
☣️ Faire attention à ne pas révéler le secret sur la route GET /api/{short}/status
! ☣️
Exercice 4 (Bonus) : Expiration de liens
Ajouter une date d’expiration optionnelle aux liens. Modifier la base de données et les routes pour que :
- À la création du lien, on peut préciser un attribut
expires_at
de type date. Modifier le validateur de la route pour ajouter cet attribut optionnel. - Lors de la visite, si le lien est expiré, on renvoie un code 404, sinon on poursuit avec la redirection.
- Ajouter un ramasse-miette qui périodiquement (e.g., toutes les 60 secondes) va supprimer tous les liens expirés de la base.
⚠️ Compléter tests/server.test.js
et tester la nouvelle fonctionnalité. ⚠️