Il s'agit d'une version statique de l'intranet d'A. Jonquet, certaines fonctionnalités sont donc potentiellement non fonctionnelles.
Rejoindre la version dynamique 🔒
R301
Navigation

Exploitation d'une API - partie 1

Ce TP sera l'occasion de mettre en pratique les connaissances acquises au cours des TP précédents.

En effet, au fil de ce TP, vous allez réaliser une page permettant de parcourir une base de données de films fournie au travers d'une API web. Les requêtes seront réalisées en AJAX et l'interaction et la mise à jour de la page seront réalisées en JavaScript.

Ce TP consistera à mettre en place la page d'exploration des films. Dans un premier temps, vous afficherez la liste des films retournée par l'API web. Puis, comme cette liste est paginée, vous ajouterez un système de pagination.

Remarque importante

Les notes des TP seront obtenues à partir de vos dépôts Git, vous devrez donc prendre grand soin de la qualité de ces dépôts et de leurs « commits ».

De manière similaire, les descriptions de vos « commits » devront être claires et informatives, afin de permettre l'évaluation de la progression de votre travail.

Objectifs de la séance

  • Manipulation du DOM
  • Utilisation de l'API fetch
  • Utilisation des promesses JavaScript
  • Exploitation d'une API web à l'aide d'AJAX
  • Approfondissement du langage JavaScript

Mise en place du projet

Comme dans le TP précédent, vous allez mettre en place un nouveau projet en vous basant le projet précédent. Vous commencerez donc par copier les fichiers nécessaires depuis votre précédent TP.

Dans un nouveau répertoire de travail nommé « r301-js-movies », vous copierez les fichiers :

  • « .eslintrc.js », le fichier de configuration d'ESLint,
  • « .gitignore », le fichier d'exclusion de Git,
  • « babel.config.js », le fichier de configuration de Babel,
  • « package.json », le fichier décrivant le projet qui contient la liste de paquets à installer. Vous l'éditerez pour modifier le projet (nom, description, repository...),
  • « webpack.config.js », le fichier de configuration de Webpack et de son serveur de développement,
  • « src/index.js », le fichier principal de la bibliothèque JavaScript, dont vous pouvez supprimer tout le contenu pour l'instant,

Cette copie peut être réalisée facilement en ligne de commande si l'on considère que votre précédent projet se trouve dans « ../r301-js-introduction/ » :

cp -r ../r301-js-introduction/{.eslintrc.js,.gitignore,babel.config.js,package.json,webpack.config.js} .
mkdir src
cp -r ../r301-js-introduction/src/{index.js} src/

Vous installerez ensuite les paquets de votre projet à l'aide de la commande suivante :

npm install

Vous copierez le fichier CSS « index.css » (télécharger) dans le sous-répertoire « public/css ». Ainsi que le fichier HTML « template.html » (télécharger) dans le répertoire « src ».

Enfin, vous pourrez créer un dépôt Git local dans lequel vous réaliserez votre commit initial contenant les fichiers précédents.

Pour finir, vous lui associerez un dépôt distant nommé « r301-js-movies » sur le GitLab du département et vous pousserez votre premier commit.

Vous contrôlerez que la copie s'est bien passée et vous ajouterez votre intervenant de TP avec un rôle de « Reporter ».

Travail à réaliser
  • Créer un répertoire local.
  • Y copier les fichiers nécessaires du TP précédent.
  • Y ajouter les fichiers « index.css » et « template.html » fournis.
  • Y créer un dépôt Git local.
  • Répliquer le dépôt local sur le serveur distant GitLab.
  • Vérifier les membres et leurs rôles.

Mise en place des tests

Comme lors du premier TP, vous allez valider votre production à l'aide de tests que vous ajouterez au fur et à mesure de votre avancée.

Pour valider la configuration de votre projet, vous allez mettre en place une fonctionnalité et un test simples.

Vous commencerez par ajouter un premier script « movies-api.js » au répertoire « src » dont l'objectif sera de fournir les fonctions permettant d'interagir avec l'API web.

Dans ce script, vous définirez une constante API_URL exportée par son nom. Cette constante recevra comme valeur l'URL de l'API web : « http://movies-api ».

Vous ajouterez ensuite dans le sous-répertoire « tests/movies-api » le script de tests « API_URL.test.js » (télécharger) suivant, permettant de valider la présence de cette constante :

Vous vérifierez que le test est bien lancé à l'aide de la commande suivante et que le code est valide :

npm run test -- --watch
Travail à réaliser
  • Mise en place de la constante API_URL dans le script « src/movies-api.js »
  • Ajout du script de tests « tests/movies-api/API_URL.test.js ».
  • Validation du code par le test.

Une première requête HTTP

Vous allez maintenant créer la fonction getAllMovies(), exportée nommément, dans le fichier « movies-api.js ». Cette fonction réalisera la requête HTTP vers la ressource « /movies » de l'API web permettant d'obtenir la liste des films à afficher et retournera une promesse JavaScript qui fournira le tableau des films décrit par le JSON contenu dans la réponse HTTP fournie par l'API web.

De manière similaire au TP précédent, vous utiliserez la méthode json() pour obtenir une promesse d'obtention du tableau JavaScript décrit dans le corps de la réponse AJAX.

Vous validerez votre code à l'aide du fichier de tests « getAllMovies.test.js » (télécharger).

Travail à réaliser
  • Création de la fonction getAllMovies().
  • Ajout des tests associés.

Création de la structure DOM présentant un film

Vous ajouterez un nouveau fichier « movies-ui.js » dans le répertoire « src ». Ce fichier accueillera toutes les fonctions d'interaction avec le document DOM HTML.

Dans ce fichier, vous créerez la fonction createMovieElt(movieData) exportée nommément, dont le rôle sera de retourner un élément DOM HTML permettant l'affichage du film dont les données sont passées en paramètre.

Les données d'un film fournies par le paramètre movieData correspondront à un élément du tableau des films fourni par l'API web et se conformera donc au schéma suivant :

La structure DOM présentant un film, retournée par la fonction createMovieElt(movieData), devra se conformer à la maquette suivante :

Maquette de l'affichage d'un film

Enfin, vous ajouterez le script de tests « createMovieElt.test.js » (télécharger) au répertoire « test/movies-ui » pour valider votre code.

Travail à réaliser
  • Création de la fonction createMovieElt(movieData).
  • Ajout des tests associés.

Remplissage de la liste de films

Maintenant que vous disposez d'une fonction pour obtenir un tableau de films depuis l'API web et d'une fonction pour produire la structure DOM présentant un film, vous allez créer la fonction permettant de mettre à jour le conteneur de films de la page, en y insérant les éléments DOM réalisant l'affichage des films obtenus depuis l'API web.

Dans le script « movies-ui.js », vous ajouterez une fonction updateMoviesElt() exportée nommément.

  • Cette fonction utilisera la fonction getAllMovies() pour obtenir le tableau des films,
  • puis invoquera la fonction createMovieElt(movieData) pour chaque film,
  • et insérera le résultat dans l'élément du document DOM de type « article » dont la classe CSS est « movies-list ».

Vous contrôlerez le bon fonctionnement de votre fonction à l'aide du fichier de tests « updateMoviesElt.test.js » (télécharger).

Vous pourrez ensuite provoquer le remplissage initial du document DOM en ajoutant l'invocation de la fonction updateMoviesElt() dans le fichier « index.js ».

Vous devriez constater qu'une liste de titre de films est bien ajoutée dans la page après son chargement initial.

Travail à réaliser
  • Création de la fonction updateMoviesElt().
  • Ajout des tests associés.
  • Utilisation de la fonction updateMoviesElt() dans le fichier « index.js ».

Gestion de l'URL du poster du film

En proposant uniquement les titres des films, l'affichage est un peu austère. Vous allez ajouter le poster de chaque film à l'affichage.

En effet, vous avez dû constater que les données de chaque film comportent une propriété poster désignant le chemin de la ressource de l'API web vers le poster du film.

La ressource « /images/{uuid}/{size} » comporte deux éléments paramétriques issus d'une route Symfony :

  • le premier uuid est l'identifiant de l'image requise,
  • le second size permet de définir la taille de l'image souhaitée ; « xsmall », « small », « medium » ou « original ».

Vous noterez au passage l'utilisation d'UUID pour la gestion des identifiants des enregistrements de la base de données. Il s'agit d'une alternative à la gestion des identifiants par entiers auto-incrémentés.

Conformément au choix d'organisation, vous placerez toutes les fonctionnalités d'interaction avec l'API web dans le fichier « movies-api.js ». Vous y ajouterez une nouvelle fonction posterUrl(imagePath, size), exportée nommément.

Cette fonction accepte deux paramètres imagePath la ressource de l'API web vers le poster et size la taille de l'image, valant « original » par défaut.

La fonction posterUrl() retournera l'URL de l'image afin qu'elle puisse être utilisée comme source d'un élément HTML de type « image ».

Le fichier de tests « posterUrl.test.js » (télécharger), à placer dans le répertoire « tests/movies-api », vous permettra de valider votre code.

Travail à réaliser
  • Création de la fonction posterUrl(imagePath, size).
  • Ajout des tests associés.

Affichage du poster du film

Pour ajouter le poster à la structure DOM présentant un film, vous allez modifier la fonction createMovieElt().

Vous ajouterez un élément DOM de type « image » dont la source désignera l'URL du poster du film de taille « medium » et dont la propriété alt contiendra « poster of 'le-titre-du-film' ».

La structure DOM HTML produite par la fonction createMovieElt(movieData) devrait maintenant correspondre à la maquette suivante :

Maquette de l'affichage d'un film avec son poster

Vous ajouterez les tests suivants au fichier « createMovieElt.test.js » pour valider votre code :

Travail à réaliser
  • Modification de la fonction createMovieElt(movieData).
  • Ajout des tests associés.

Extraction de la pagination

En vous référant à la documentation de l'API web de la ressource « /movies », vous constaterez que la liste des films est paginée, mais que vous obtenez par défaut uniquement la première page.

Si vous observez les en-têtes HTTP produits par l'API web, vous constaterez que les informations de pagination y sont définies :

  • « Pagination-Current-Page » contient le numéro de la page de la réponse,
  • « Pagination-Items-Per-Page » contient le nombre de films par page,
  • « Pagination-Last-Page » contient le numéro de la dernière page de films,
  • et « Pagination-Total-Items » contient le nombre total de films.

Afin de permettre à l'utilisateur de naviguer entre les différentes pages de films de l'API web, vous devez disposer de ces informations.

Dans le fichier « movies-api.js », vous allez créer une nouvelle fonction extractPaginationFromHeaders(response) exportée nommément.

Elle recevra en paramètre une instance de réponse AJAX, dont vous allez extraire la pagination.

Cette fonction retournera un objet JavaScript comportant deux propriétés :

  • current contenant un entier obtenu à partir de l'en-tête « Pagination-Current-Page »,
  • et last contenant un entier obtenu à partir de l'en-tête « Pagination-Last-Page »,

Pour rappel, la conversion d'une chaîne de caractères en entier est réalisée à l'aide de la fonction parseInt().

Vous validerez votre code à l'aide du fichier de tests « extractPaginationFromHeaders.test.js » (télécharger).

Travail à réaliser
  • Création de la fonction extractPaginationFromHeaders(response).
  • Ajout des tests associés.

Fusion de la collection de films et des données de pagination

Dans le but de simplifier la récupération du contenu paginé, vous allez ajouter la fonction exportée nommément extractCollectionAndPagination(response) au fichier « movies-api.js ».

Le rôle de cette fonction sera de retourner une promesse d'obtention d'un objet JavaScript contenant deux propriétés :

  • pagination, les données de pagination extraites des en-têtes de la réponse AJAX transmise en paramètre (response),
  • et collection, le tableau des éléments décrit au format JSON dans le corps de la réponse AJAX transmise en paramètre (response).

Plutôt que de produire vous-même une promesse, vous pourrez retourner la promesse produite par la méthode json() à laquelle vous aurez chaîné la transformation du résultat en l'objet JavaScript souhaité.

Le fichier « extractCollectionAndPagination.test.js » (télécharger) vous permettra de valider votre code.

Travail à réaliser
  • Création de la fonction extractCollectionAndPagination(response).
  • Ajout des tests associés.

Gestion de la pagination lors de la réponse HTTP

Vous allez modifier la fonction getAllMovies() afin qu'elle retourne la promesse d'un objet JavaScript contenant la collection et la pagination obtenues à l'aide de la fonction extractCollectionAndPagination(response).

La fonction updateMoviesElt() ne devrait plus fonctionner, car le paramètre, obtenu par la fonction de rappel attachée à l'aide de la méthode then de la promesse retournée par getAllMovies(), n'est plus un tableau mais un object JavaScript contenant le tableau dans sa propriété collection.

Vous corrigerez donc le problème en utilisant la propriété collection du paramètre de la fonction de rappel.

Vous remplacerez les fichiers de tests « getAllMovies.test.js » (télécharger) et « updateMoviesElt.test.js » (télécharger) par les fichiers fournis afin qu'ils prennent en compte ces modifications.

Tous les tests devraient de nouveau être valides.

Travail à réaliser
  • Utilisation de la fonction extractCollectionAndPagination(response) dans la fonction getAllMovies().
  • Modification de la fonction updateMoviesElt().
  • Mise à jour des tests « getAllMovies.test.js » et « updateMoviesElt.test.js ».

Affichage d'un des boutons de la pagination

Vous allez créer la fonction qui produit l'élément DOM représentant un bouton de l'interface permettant d'interagir avec la pagination.

Vous ajouterez donc la fonction createPaginationButtonElt(materialIcon, isDisabled, page), exportée nommément, au fichier « movies-ui.js ».

Cette fonction retournera un élément DOM de type « button » :

  • il contiendra une icône Material Symbol,
  • le bouton pourra être désactivé
  • et lorsqu'il est cliqué, il invoquera la fonction updateMoviesElt en lui transmettant en paramètre le numéro de la page souhaitée.

Pour paramétrer le bouton retourné, la fonction reçoit 3 paramètres :

  • materialIcon le texte de l'icône Material Symbol,
  • isDisabled un booléen identifiant si le bouton doit être désactivé
  • et page, le numéro de la page vers laquelle le bouton doit mener.

La structure du bouton devra correspondre à la maquette suivante :

Maquette de l'affichage d'un bouton de la pagination

Vous ajouterez le fichier « createPaginationButtonElt.test.js » (télécharger) à votre base de tests afin de valider votre code.

Travail à réaliser
  • Création de la fonction createPaginationButtonElt(materialIcon, isDisabled, page).
  • Ajout des tests associés.

Nettoyage d'un élément DOM

Lors de la modification de l'affichage de la collection de films, vous allez devoir nettoyer la structure DOM précédente pour pouvoir modifier la collection de films sans que ces films s'ajoutent au précédent affichage. De manière similaire, l'élément DOM de la page contenant la pagination devra lui aussi être vidé avant chaque modification.

Vous ajouterez donc la fonction emptyElt(elt), exportée nommément, dans le fichier movies-ui.js. Son rôle sera de vider de tous les fils de l'élément DOM transmis en paramètre.

Vous utiliserez les méthodes et attributs d'instance de la classe Node de l'API DOM et plus particulièrement hasChildNodes, firstChild et/ou removeChild.

Le fichier de tests « emptyElt.test.js » (télécharger) vous permettra de valider votre code.

Travail à réaliser
  • Création de la fonction emptyElt(elt).
  • Ajout des tests associés.

Création de la structure DOM présentant la pagination

Vous allez maintenant créer la fonction permettant de produire la structure DOM de manipulation de la pagination à partir de l'objet JavaScript décrivant la pagination obtenue dans les en-têtes de la réponse HTTP de l'API web.

Vous créerez la fonction updatePaginationElt(pagination), exportée nommément, dans le fichier movies-ui.js.

Cette fonction injectera la structure DOM de la pagination dans l'élément DOM du document prévu à cet effet (« nav.pagination »).

La fonction updatePaginationElt() accepte un paramètre pagination, qui recevra le contenu de la propriété pagination de l'objet promis par la fonction getAllMovies().

La structure de la pagination devra correspondre à la maquette suivante :

Maquette de l'affichage de la pagination

Vous utiliserez des icônes Material Symbols pour illustrer les boutons de navigation de la pagination :

Le fichier de tests « updatePaginationElt.test.js » (télécharger) vous permettra de valider votre code.

Travail à réaliser
  • Création de la fonction updatePaginationElt(pagination).
  • Ajout des tests associés.

Affichage d'un indicateur d'activité

Vous créerez la fonction setLoading(), exportée nommément, dans le fichier movies-ui.js, dont le rôle sera de vider les nœuds DOM de la collection de films et de la pagination puis d'afficher un indicateur d'activité pendant le chargement des données.

Cette fonction

  • videra le conteneur DOM de la pagination « nav.pagination »,
  • remplacera le contenu du conteneur DOM « article.movies-list » par la structure suivante.
Maquette de l'indicateur d'activité

Vous utiliserez le fichier de tests « setLoading.test.js » (télécharger) pour valider votre code.

Une fois les tests validés, vous invoquerez cette fonction dans la fonction updateMoviesElt() avant de réaliser la requête HTTP et vous viderez le conteneur DOM de films (« article.movies-list ») lors de la réception de la réponse de l'API web, avant d'afficher les films.

Travail à réaliser
  • Création de la fonction setLoading().
  • Ajout des tests associés.

Affichage de la pagination dans la page

Pour finaliser la mise en place de la pagination, lors de la requête de la collection des films à afficher, vous allez devoir transmettre à l'API web le numéro de la page souhaitée par l'utilisateur.

Vous commencerez par modifier la fonction getAllMovies() pour lui ajouter un paramètre page, avec une valeur par défaut de 1, qui représentera le numéro de la page à afficher. Ce numéro de page sera transmis à l'API web sous la forme du paramètre d'URL page.

Ensuite, vous ajouterez un paramètre page, avec une valeur par défaut de 1, à la fonction updateMoviesElt(). Vous transmettrez ce paramètre à la fonction getAllMovies() afin d'obtenir un tableau de films correspondant à la page souhaitée.

Et lors de la réception de la réponse de l'API web, vous effectuerez la mise à jour de la pagination en invoquant la fonction updatePaginationElt() avec les données de pagination de la réponse en paramètre.

Travail à réaliser
  • Ajout d'un paramètre page à la fonction getAllMovies() avec 1 comme valeur par défaut.
  • Ajout d'un paramètre page à la fonction updateMoviesElt()
  • Affichage de la pagination lors de la réponse de l'API web pour la collection de films.
A. Jonquet DUT-INFO/REIMS