Introduction aux APIs RESTful (REpresentational State Transfer). Principes, concepts et bonnes pratiques des services web REST. Implémentation avec Jakarta RESTful Web Services.
Ce document présente les service Web REST en général et par la pratique en Java.
Il s’appuie sur un exemple simple d’application : https://github.com/ebpro/sample-jaxrs qui servira à illustrer les notions et sera étudiée en détail dans la partie pratique.
L’idée générale de l’approche REST (REpresentational State Transfer) pour construire une interface de programmation (API) est d’offrir un accès distant à des ressources via une interface commune construite au dessus de “en” http. On parle d’approche RESTful quand l’interface d’une application est conforme à une certaine philosophie (il ne s’agit pas d’une norme).
En particulier, le fait que l’API est sans état côté serveur permet de l’utiliser de façon transparente même en cas de serveur proxy/cache.
Important
RESTfull est une approche d’API client/serveur suivant la logique de navigation dans un hypermedia. On parle d’HATEOS (Hypermedia As The Engine Of Application State).
Pour définir un protocole de communication, il faut généralement définir :
un système d’identification (d’adressage) des ressources manipulées,
un protocole de communication,
un format d’échange de données éventuellement typées,
un système de gestion des erreurs.
La logique RESTfull est d’utiliser tout ce que propose HTTP pour écrire une API en HTTP.
L’adressage des ressources
Important
Les ressources (ou ensembles de ressources) de l’application sont identifiées par des URI. Les URL sont une sorte particulière d’URI qui indique un moyen d’accès en plus de les identifier de façon unique.
Il n’y a pas de standard pour les API REST. Il vaut généralement mieux rester simple et cohérent. Quelques pratiques sont utilisées classiquement :
On utilise des noms (pas des verbes) au pluriel pour les ressources :
# Toutes les personnes
http://MyServer/MyApp/Persons
La ou les informations qui permettent d’identifier une ressource sont inclues dans l’URL et le plus possible dans le chemin plutôt que dans la Query String (par exemple un identifiant) :
# La personne d'identifiant 1
http://MyServer/MyApp/Persons/1
On évite les “jointures” dans les chemins. Si on le fait, l’ordre doit être constant et logique (la fin du chemin correspond toujours à la ressource retournée).
Les chiens de la personne 1
http://MyServer/MyApp/Persons/1/Dogs
http://MyServer/MyApp/Dogs?master_id=1
On utilise la pagination, le filtrage et le tri (via les Query Strings) pour les requêtes complexes et pour contrôler le volume des données retournées. A noter la possibilité d’utiliser les Matrix Params même s’ils ne sont pas standards.
La deuxième page de personnes en utilisant des pages de 10 personnes.
http://MyServer/MyApp/Persons?page=2&page_size=10
http://MyServer/MyApp/Persons;page=2;page_size=10 (avec des Matrix Params)
filtre qui trie par ordre decroissant de date de création, puis par titre
Des éléments “administatifs” peuvent/doivent être proposés (par exemple pour gérer la version d’une API en ajoutant /api/v1, /api/v2, … au début du chemin).
Le protocole d’échange
Important
Les actions sur les ressources (identifiées par des URIs) sont associées aux verbes (méthodes) standards du protocole HTTP.
REST s’appuie sur le protocole HTTP (HyperText Transfert Protocol) qui est défini dans les RFC 7230 à 7237. La RFC 7231 défini les méthodes et les codes de retour.
Une méthode est “sure” (safe) si elle ne modifie pas l’état de serveur.
Une méthode est idempotente (idempotent) si l’effet attendu par des appels multiples est identique à un appel unique de la même requête. Les méthodes sures sont donc idempotentes.
Donc en particulier GET ne modifie rien, plusieurs appels à PUT n’ajoutent ou n’appliquent une modification qu’une fois mais plusieurs appels à POST en ajoutent plusieurs.
Attention, certains proxies HTTP peuvent empêcher certaines actions en dehors de GET et POST (cf. X-HTTP-Method-Override). Cela peut donc conduire à devoir enfreindre les règles ci-dessus.
Un endpoint REST est défini par un verbe HTTP et une URL.
Obtenir toutes les personnes :
GET http://MyServer/MyApp/Persons
Obtenir une personne précise par identifiant :
GET http://MyServer/MyApp/Persons/1
Obtenir toutes les personnes entre 7 et 16ans (avec un filtre) :
GET http://MyServer/MyApp/Persons?ageMin=7&ageMax=16
Supprimer toutes personnes
DELETE http://MyServer/MyApp/Persons
Supprimer une personne
DELETE http://MyServer/MyApp/Persons/1
La représentation des ressources
Important
Les resources sont généralement représentées et échangées à l’aide de langages autodescriptifs comme XML ou JSON.
Les types de données envoyées ou attendues sont indiqués dans l’entête de la requête HTTP par Content-Type: et Accept:. Pour cela, on utilise les Internet Media Types (ex MIME Type - Multipurpose Internet Mail Extensions). Il s’agit d’une liste standard de formats et de sous-formats d’échange de données (text/plain, text/xml, application/json, …).
L’exemple ci-dessous sérialise des objets Java qui représente un auteur et un livre en JSON et en XML. (Le détail est expliqué plus loin).
Le protocole HTTP défini un ensemble de codes de retours. Il est donc possible d’utiliser ces codes standards comme code de retour pour indiquer comment l’opération a réussi ou pourquoi elle a échoué.
Important
Le code de retour des méthode est un code HTTP. Il est indiqué de façon standard dans l’entête de la réponse et peut être répété dans le contenu si une enveloppe est proposée.
Le code de retour des méthodes est un code HTTP.
Il est indiqué de façon standard dans l’entête de la réponse.
Il peut être répété dans le contenu si une enveloppe est proposée.
Code
Signification
Usage
200
Ok
Requête traitée avec succès.
201
Created
Nouvelle ressource créée.
204
No Content
Pas de contenu, pas exmple lors d’une requête DELETE réussie.
206
Partial Content
Seulement une partie de résultat est retourné par exemple en cas de pagination (non explicite).
304
Not Modified
Utilisation du cache possible.
Code
Signification
Usage
400
Bad Request
La requête est invalide et ne peut pas être traitée par le serveur.
401
Unauthorized
La requête nécessite que le client soit authentifié.
403
Forbidden
Le client est authentifié mais l’utilisateur n’est pas autorisé à accéder à cette ressource.
404
Not Found
La ressource demandée n’existe pas.
500
Internal Server Error
C’est une erreur générique de fonctionnement, elle devrait toujours être accompagnée d’une description
Un échange REST = un échange HTTP
Important
Un échange d’une API REST correspond donc exactement à un échange http.
Une requête HTTP
composée d’un verbe, d’une URL, de la version de HTTP utilisée, d’un en-tête (une liste de couples nom:valeur par exemple Content-Type: text/xml) et un corps éventuellement vide (les données envoyées).
Une réponse HTTP
composée d’un code de retour, de meta données dans l’en-tête et d’un corps qui contient les données. Le corps est éventuellement encapsulé dans une “enveloppe” qui reprend les meta données pour faciliter leur traitement.
Requête de modification d’une personne (id dans l’URL):
PUT http://MyServer:8080/MyApp/Persons/1
Host: MyServer:8080
Content-Type: application/json; charset=utf-8
Content-Length: 12
{"age":"18"}
Utilisation
Une requête REST peut être envoyée par programmation ou en utilisant un programme dédié comme curl en ligne de commande, postman pour chrome ou RestClient pour firefox.
Regardez les options de la commande curl pour réaliser des requêtes HTTP.