TP 4 : Web APIs (programmation REST)

Objectifs pédagogiques du TP

Références

Vous puiserez dans le cours de REST et en particulier, les références en fin de cours.

Préambule

Dans ce TP, vous repartirez du back-office de l'application de blog réalisée dans le TP précédent. Vous l'améliorerez pour faire en sorte que les objets métier de cette application soient gérés sous forme de ressources. Vous l'exposerez sous la forme d'une Web API.

Dans un premier temps, vous conserverez la méthode d'authentification utilisée dans le TP précédent (cookies + Filter). À la fin du TP, vous remplacerez cette méthode par l'utilisation de Json Web Tokens (JWT).

Outils

Vos utiliserez les outils suivants pour tester votre Web API :

Ressources

Au TP précédent, vous avez approfondi deux cas d'utilisation de l'application : la gestion des groupes et d'un billet d'un groupe. Le travail qui doit déjà être fait est que les ressources exposées par votre application (groupes, billets), ont chacune une URI qui lui est propre et que le serveur renvoie une réponse à une requête vers cette URI. De la même façon, vous avez une autre servlet (User), qui sera à terme destinée à gérer les utilisateurs.

Modification des URLs

Dans les annotations de vos contrôleurs et le fichier XML (pour les filtres), modifiez les URLs pour qu'elles correspondent à des URLs de ressources en REST. Procédez de la façon suivante :

  1. Définissez l'arborescence de vos ressources métier et l'ensemble des URLs qui leur correspond.
  2. Une fois vos URLs définies, le plus simple est de réaliser une servlet principale (front controller, ou routeur) que vous mapperez à la racine de votre application et qui sera responsable de l'aiguillage des requêtes vers les contrôleurs de cas d'utilisation. Pour cela, parsez les chemins de vos URLS (request.getRequestURI() peut vous y aider) et découpez les chemins pour récupérer :
    • les noms génériques des ressources de type collection,
    • les identifiants des instances de ressources.
    Pour chaque type d'URL correspondant à un contrôleur, ajoutez les attributs nécessaires au traitement de la requête et faites une redirection interne vers ce contrôleur.
  3. Pour les filtres : le plus simple est d'intercepter toutes les URLs à partir d'un chemin donné (par exemple : /* pour le filtre d'authentification), et de définir une variable contenant l'ensemble des URLs à ignorer (chain.doFilter()).

Aide pour la réalisation du routeur :

Représentations des ressources

En REST, le client et le serveur échangent des représentations de ressources, éventuellement partielles. L'objectif de cette partie est de définir, comme cela a été précisé en cours, les contenus des requêtes et des réponses échangées par votre API. Concernant le format, pour l'instant, vous pouvez continuer à renvoyer uniquement des réponses en HTML (vous étendrez cela dans la question sur la négociation de contenus).

Contenus des requêtes

Contenus des réponses

Pour l'instant, vous pouvez laisser les JSP qui composent les réponses en HTML, mais assurez-vous qu'elles renvoient bien des contenus en lien avec les requêtes (par exemple la liste des groupes sur l'URL /groupes).

Sémantique de HTTP

Faites en sorte que :

Transactions sans état

Contexte des requêtes

Vous allez maintenant modifier le fonctionnement interne de l'application en faisant en sorte que le contexte des requêtes soit géré par le client et non pas en interne du serveur.

Remarque : pour l'instant, ne vous préoccupez pas des liens entre les ressources. Par exemple, le champ "auteur" d'un billet n'est qu'un String sans signification, et le serveur n'a pas à vérifier qu'il correspond réellement à un utilisateur.

Authentification Stateless

Pour cette partie, vous vous aiderez d'une bibliothèque externe : Java-JWT. Vous utiliserez cette bibliothèque (et sa documentation) pour remplacer l'authentification par session par de l'authentification par JWT. Pour cela :

  1. Ajoutez la dépendance Maven
  2. Dans le contrôleur du CU de login (servlet Init ou User), remplacez la création de session par celle d'un token "simple" JWT. Le payload ne contiendra que 2 "claims" :
    • l'URI complète de l'utilisateur (claim = "sub" : subject)
    • l'autorité qui a émis le token ("iss" : issuer)
  3. Dans un premier temps et pour pouvoir tester votre application, placez le token dans un cookie qui sera envoyé au client, et que celui renverra automatiquement au serveur à chaque nouvelle requête
  4. Dans le filtre d'authentification :
    1. accédez au token
    2. validez le token
    3. s'il est valide, rajoutez le login contenu dedans en attribut de requête et "laissez passer" la requête
    4. redirigez vers la page d'accueil (comme précédemment) sinon
  5. Rajoutez une durée de vie de la session (courte pour pouvoir tester) dans le payload, et faites en sorte qu'elle soit prise en compte dans la validation

Négociation de contenus

Vous allez maintenant permettre aux clients de spécifer le format dans lequel ils obtiendront des représentations de ressources :

Pour améliorer la cohésion des contrôleurs et éviter la duplication de code, vous allez découpler le pattern MVC de la négociaton de contenus (voir plus bas), vous allez "couper" votre MVC en deux, à l'aide d'un pattern DTO et déléguer la responsabilité de la négociation de contenus à un filtre.

  1. regroupez les différents types de vue pour chaque ressource dans un dossier commun (sous-dossier de WEB-INF).
  2. dans les contrôleurs, positionnez un attribut de requête qui indique le nom du dossier contenant les différentes vues de la ressource
  3. mettez en place des Data Transfer Objects (DTO) qui pourront contenir les données des représentations de vos modèles
  4. dans les contrôleurs, instanciez un DTO contenant les données nécessaires et rajoutez-le en attribut de requête
  5. créez un filtre qui intercepte les requêtes après leur traitement par le contrôleur et dont la responsabilité sera de gérer la négociation de contenus
  6. dans le fichier web.xml, rajoutez des paramètres d'initialisation du filtre, pour indiquer le début du chemin d'accès à ce fichier, et éventuellement, les suffixes des fichiers qui contiennent les vues
  7. dans le filtre, accédez au header Accept de la requête, et en fonction de sa valeur, incluez la vue correspondante

Aide pour la génération de contenus HTML avec des JSP :

Hypermédia

Ajout de liens

Faites en sorte que les représentations de chaque ressource contiennent des liens vers les ressources apparentées ; par exemple, la représentation du groupe devrait contenir un lien vers chaque billet, et les champs de type String représentant les auteurs d'un billet ou d'un commentaires devront être remplacés par les URI des ressources.

Lorsqu'une ressource a été créée, un lien doit être renvoyé (header HTTP Location de la réponse), contenant l'URI de cette nouvelle ressource.

Documentation de l'API

Logiquement, vous devriez également écrire la documentation de votre API. Pour vous faire gagner du temps (et à nous aussi pour la correction), cette documentation vous est fournie ici. Elle est décrite en OpenAPI, et utilisable dans Swagger. Vous pouvez la visualiser et tester votre API en ligne à l'URL http://editor.swagger.io/.

Remarque : pour pouvoir tester voter API depuis l'éditeur en ligne de Swagger, il faut que Tomcat l'autorise à lui envoyer des requêtes, à l'aide du mécanisme Cross-Origin Resource Sharing (CORS). Pour cela, vous devez rajouter la config ci-dessous (avant les autres filtres) dans le fichier web.xml.

  <filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
      <param-name>cors.allowed.origins</param-name>
      <param-value>http://editor.swagger.io</param-value>
    </init-param>
    <init-param>
      <param-name>cors.allowed.methods</param-name>
      <param-value>GET,POST,PUT,DELETE</param-value>
    </init-param>
    <init-param>
      <param-name>cors.support.credentials</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Finalisation de l'API

Faites en sorte que votre API corresponde à la description fournie à la question précédente.

Instructions de rendu

Vous tagguerez la dernière version pushée sur la forge de votre Web API en REST avec le tag "TP4", et vous déploierez cette version sur votre VM à l'URL https://192.168.75.xx/api/v2/ ; le dernier push ainsi taggué doit dater au plus tard du mardi 12 novembre 2019 au soir.

Licence Creative Commons
Valid XHTML 1.0 Transitional