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 champ uri 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 ou curl 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 et npm 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 de GET /api/{short} pour l’utiliser.
  • 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é. ⚠️