devweb

Projet : réducteur d’URL en Node.js/Express

Ce projet consiste à réaliser un service simple de réduction d’URL comme https://bit.ly/ ou https://tinyurl.com/ Il s’agit d’abord de la réalisation d’une API serveur REST puis d’un client :

Un projet d’application est disponible sur Github https://github.com.

Introduction

Le service à réaliser permet de transformer une URL longue, comme https://nodejs.org/api/http.html#event-connect_1 en une URL courte http://localhost/WmFJQp qui redirige vers l’URL d’origine quand on se rend dessus. Le service propose les routes suivantes, qui répondent des documents JSON (en-tête Content-Type: application/json) :

La route suivante en revanche, ne répond pas de JSON mais redirige le navigateur :

Installation

Créer votre dépot sur GitHub puis cloner votre projet.

Vous disposez d’un projet de départ fonctionnel où les routes GET / et POST / de l’API V1 sont déjà implémentées. Une route GET /error qui génère une erreur 500 est aussi créée pour les tests. En revanche, les routes GET /:url et GET /status/:url ne sont pas implémentées et renvoient pour l’instant une erreur 501.

Avant de démarrer, créer un fichier nommé .env à la racine du projet avec le contenu comme suit, à adapter à votre environnement si besoin. Ce fichier .env est automatiquement chargé par l’application pour définir les variables d’environnement nécessaires à l’exécution de l’application.

PORT=8080
LINK_LEN=6
DB_FILE=database/database.sqlite
DB_SCHEMA=database/database.sql

Lancement

La base de données database/database.sqlite est re-créée, si nécesaire, automatiquement par l’application. Vous pouvez y accéder avec votre interface SQLite favorite comme https://sqlite.org (utiliser une version récente).

Après avoir installé puis lancé l’application, consultez http://localhost:8080/api-docs qui donne une documentation Swagger UI interactive pour vérifier que tout fonctionne.

Tests

Pour les tests manuels, sans utiliser Swagger, installez https://httpie.io/ (recommandé) ou https://curl.se/ (le plus connu, mais moins facile) et exécutez une des commandes suivantes selon le logiciel installé :

## exemple de requête GET
# pour curl
curl --include --header 'Accept: application/json' --request GET http://localhost:8080/api-v1/
# pour httpie
http http://localhost:8080/api-v1/

## exemples de requêtes POST
# pour curl
curl --include --header 'Accept: application/json' --header 'Content-Type: application/json' --request POST http://localhost:8080/api-v1/ --data '{"url": "https://perdu.com"}'
# pour httpie
http POST http://localhost:8080/api-v1/ url="https://perdu.com"

Une documentation complète est fournie sur le chemin http://localhost:8080/api-docs/. Cette documentation est interactive et vous permet d’envoyer des requêtes comme les précédentes via son interface, ceci permet de tester les différentes routes déjà implémentées et celles à réaliser ensuite.

La documentation est entièrement générée à partir du d’une spécification écrite au format YAML dans le fichier static/open-api.yaml. Le middleware Swagger UI Express permet de faire le rendu.

NOTA BENE la page http://localhost:8080/api-docs/ est très importante pour tout le déroulement du projet car elle vous permet de tester vos fonctionnalités.

Modalités de rendu

Le projet est à rendre sur Github https://github.com et sur Render https://render.com

À chaque partie complétée, il faut associer un tag GIT. Penser également à compléter le fichier README.md avec votre état d’avancement.

critères d’évaluation

L’évaluation des fonctionnalités sera en partie automatisée, il faut donc respecter srupuleusement les schéma des réponses JSON demandés.

NOTA BENE Pour ajouter un tag, utiliser la fonctionnalité de VSCode, l’interface Web de GitHub ou la commande git comme git tag mon-tag main et git push origin mon-tag. Dans tous les cas pensez à pousser les tags sur le dépôt GitHub, les tags ne sont transmis qu’avec un push spécifique.

Partie 1 : prise en main

Répondre aux questions précédentes dans le fichier REPONSES.md de votre dépôt.

Pousser le fichier REPONSES.md dans votre dépôt pour le jeudi 1er septembre 23h59. Mettre le tag reponses à la version correspondant dans votre dépôt Git.

Partie 2 : compléter l’application

Dans cette partie, il n’y a pas encore de front-end, il s’agit uniquement d’un back-end qui va recevoir des requêtes HTTP GET ou POST et répondre des contenus JSON ou rediriger sans aucune CSS ni HTML.

NOTA BENE il faut respecter les spécifications fournies pour ces fonctionnalités, dont notamment la structure des objets JSON des réponses.

Réaliser ces fonctionnalités et les pousser dans le dépôt. Mettre le tag api-v1 à la version correspondant dans votre dépôt Git.

Conseils

Partie 3 : négociation de contenus et réponse HTML

Dans cette partie on va adapter le type de la réponse à la demande du client, c’est-à-dire fournir une réponse JSON comme précédement ou une réponse HTML (générée côté serveur) selon ce que l’utilisateur souhaite via l’en-tête de requête Accept.

La méthode res.format() de la classe Response d’Express permet de faire de la négotiation de contenu, c’est-à-dire, d’adapter le format de la réponse (en-tête de réponse Content-Type) à ce que l’utilisateur accepte (en-tête de requête Accept).

Ainsi, réorganisez les routes de l’application pour que chacune réponse soit fournie soit en application/json soit en text/html selon ce que l’utilisateur a démandé :

En cas d’un autre format que JSON ou HTML, retourner une erreur HTTP 406 Not Acceptable.

Pour cela créer un nouveau routeur que vous brancherez sur la route api-v2, en vous inspirant de ce qui est fait pour la version 1 mais en ajoutant la négociation de contenus.

Faire une première version HTML basique, puis utiliser des templates https://ejs.co/ pour faire le rendu avec la méthode response.render() et réemployant le template views/root.ejs existant. A titre d’exemple, voici le rendu des différentes pages :

formulaire de saisie

affichage après création réussie

Une base de départ du formulaire HTML est la suivante :

<form method="post" action="/api-v2/" id="submit-link">
  <label for="url">Type the URL to shorten</label>
  <input name="url" id="url" type="url" placeholder="https://perdu.com" />
  <button type="submit">Submit</button>
</form>

Réaliser ces fonctionnalités et les pousser dans le dépôt. Mettre le tag api-v2 à la version correspondant dans votre dépôt Git.

NOTA BENE pensez à choisir le bon serveur pour l’API v2 en haut dans l’interface de Swagger, comme dans capture d’écran ci-dessous.

choix de l'API dans Swagger

Partie 4 : client AJAX de l’API v2

Il s’agit maintenant de créer un client de type Single Page Application. Cette fois-ci, le HTML static/client.html et le fichier static/app.js seront directement servis statiquement par Express, sans utilisation de moteur template.

Le client, reprendra l’interface précédente mais cette fois-ci, tous les échanges entre le navigateur et le serveur se feront en JSON sur l’API v2 via des appels fetch. Tout se déroulera dans une page unique index.html qui contiend un formulaire de saisie d’URL et affiche le lien raccourci ou une erreur le cas échéant. Quand on soumet le forumaire, c’est une requête POST / qui est émise dont le retour JSON sert à mettre à jour la page.

On ne demande pas d’implémenter d’équivalent de GET /status/:url. Pour la redirection, il n’y a rien à faire de plus que l’API v2.

Pour faciliter l’utilisation, quand un lien est généré avec succès, on proposera un bouton Copier l’URL qui copie le lien dans le presse-papier grâce à la Clipboard.writeText() de la Clipboard API cmme dans l’image ci-dessous :

capture d'écran d'un lien raccourci réussi

NOTA BENE La page index.html pourrait être servie par un autre serveur que celui de l’API, par exemple avec python -m http.server. Si vous le tester, il faudra modifier la première ligne de static/app.js par const originURL = "http://127.0.0.1:8080/"; avec votre serveur Node.js.

Réaliser ces fonctionnalités et les pousser dans le dépôt. Mettre le tag client-ajax à la version correspondant dans votre dépôt Git.

Partie 5 : gestion de la suppression des liens

Maintenant, on souhaite ajouter une fonctionnalité de suppression de lien raccourci. Pour cela, on créé une route DELETE /api-v2/:url qui supprime le lien, mais on veut contrôler que seul l’auteur puisse supprimer en lui donnant un code secret généré lors de la création du lien. Ce secret devra être fourni lors de la requête de suppression dans l’en-tête X-API-Key pour que celle-ci réussisse.

Tout d’abord, il faut ajouter cette fonctionnalité dans la documentation en complétant le fichier static/open-api.yaml :

Ensuite :

Tester que la documentation interactive fonctionne bien. Si la spécification est bonne, vous aurez un champ de saisie avec un petit cadenas dans l’interface Swagger comme suit pour saisir l’en-tête X-API-KEY:

saisie de la X-API-KEY

Vous pouvez aussi tester avec les commandes suivantes, par exemple pour supprimer le lien HdPWk7 avec la clef RatQak :

# pour curl
curl --include --header 'Accept: application/json' --header 'X-API-KEY: RatQak' --request DELETE http://localhost:8080/api-v2/HdPWk7
# pour httpie
http DELETE http://localhost:8080/api-v2/HdPWk7 X-API-KEY:RatQak

NOTA BENE faire attention à ne pas révéler le secret sur la route GET /:url en JSON.

NOTA BENE on de demande pas de front pour cette fonctionnalité, juste la mise-à-jour de l’API v2 et de la documentation OpenAPI.

Réaliser ces fonctionnalités et les pousser dans le dépôt. Mettre le tag api-v2-delete à la version correspondant dans votre dépôt Git.