REST en JAVA avec la JSR-311
La JSR 311 JAX-RS est le pendant REST de la JSR 224 JAX-WS.Elle marque la volonté de la part de la communauté Java de cadrer, tout comme pour la stack WS-*, le développement des applications JAVA orientées ressources. Bien qu’étant sur le point d’être finalisée (elle vient de passer le Final Approval Ballot), elle est déjà implémentée par la plupart des frameworks REST du moment (Jersey, RESTeasy, CXF, une extension existe pour Restlet, …). La suite de ce billet présente les annotations de la JSR en regard des principes REST qu’elles mettent en oeuvre.
Quels sont donc les apports de cette JSR dans le développement d’applications Java orientées ressources ? Afin de respecter le style architectural REST, il est nécessaire de suivre certaines règles. Ces règles vous pouvez les retrouver dans la thèse de Roy Fielding, le livre Restful Web Services ou avec une simple recherche sur le Web. Dans cet article, je me suis librement inspiré d’une présentation de Paul Sandoz (commiteur Jersey / JSR-311) à Java One. Les exemples de code présentés utilisent Jersey [1].
La ressource REST
En REST, une ressource représente une chose suffisamment importante à vos yeux pour être référencée. Ce n’est pas obligatoirement l’exposition d’un tuple de votre base de données. Cela peut tout aussi bien être le résultat d’un algorithme, un document, une liste d’objets sérialisés, … De manière générale, tout ce qui peut être stocké sur un ordinateur ou représenté sous la forme d’un flux de bits peut être considéré comme une ressource. On référence une ressource en lui associant un identifiant unique : on s’appuie sur la notion d’URI du protocole HTTP. C’est le moyen univoque d’accéder à une ressource.
Quelques exemples d’URI
-
http://www.monserveur.com/customers : Pointe sur l’ensemble des clients
-
http://www.monserveur.com/customers/12 : Pointe sur le client dont l’identifiant technique est 12
-
http://www.monserveur.com/orders/XXXX/customers : Pointe sur les clients dont l’ordre à pour identifiant XXXX
Annotation @Path
La JSR-311 définit l’annotation @Path : elle permet de lier une ressource à une URI.
L’annotation @Path en combinaison avec les @PathParam / @QueryParam permet de gérer les URLs paramètrables.
De même, @QueryParam(”maVar”) retourne la valeur du paramètre de l’url http://monServeur/monContexte/customers/{email}?maVar=12.
Annotations @Path, @PathParam, @QueryParam
Vous souhaitez accéder à une ressource Customer, dont l’identifiant unique est son adresse mail. On souhaite donc effectuer une requête du type : GET http://monServeur/monContexte/customers/toto@toto.com
Principe 2 - Use standard methods : utilisation des méthodes HTTP
Les architectures REST doivent respecter le standard HTTP, tant dans les codes retours que dans l’utilisation même des verbes HTTP (définie par la RFC 2616 ).
But Accéder à une ressource, potentiellement en cache. Créer une ressource (identifiant inconnu) Créer / Mettre à jour une ressource (identifiant connu) Identique à GET mais aucun contenu dans le corps la réponse. Utile notamment pour vérifier la validité d’une ressource, son accessabilité, …
Méthodes
GET
POST
PUT
DELETE
Supprimer une ressource
HEAD
-
GET sur http://www.monserveur.com/customers : Totalité des clients
-
POST sur http://www.monserveur.com/customers : Création d’un client
@GET, @POST, @DELETE, @PUT, @HEAD
Dans l’exemple ci-dessus, l’annotation @GET, associée au @Path, permet de router toutes les requêtes de type GET /customers/{email} sur la méthode getCustomer(String email). @GET, @POST, @DELETE, @PUT, @HEAD agissent simplement en combinaison de @PATH comme un dispatcher.
Principe 3 - Link things together : Lier les ressources entre elles.
Afin de permettre la navigabilité entre les ressources exposées, il est nécessaire de les lier entres elles. @Context private UriInfo uriInfo; // Injecté directement dans la ressource … // Récupere le path courant UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder(); // Crée l’uri pour accéder à la nouvelle ressource URI uri = uriBuilder.path(customer.getId()).build(); // Retourne la réponse avec la nouvelle ressource return Response.created(uri).entity(customer).build(); } Dans cet exemple, on utilise les champs location et entity définit dans une réponse HTTP :
-
location : l’uri de nouvelle ressource Customer
- entity : représentation de la ressource Customer créé.
Pour une ressource, identifiée par une URI, on peut avoir de multiples représentations. Les plus courantes étant :
-
XML
-
JSON
-
(X)HTML
-
ATOM
Ce principe repose sur la négociation de contenu possible grâce à HTTP. A l’envoi d’une requête HTTP, le champ Accept défini dans le header de la requête http, peut prendre plusieurs valeurs (classés par ordre de préférences) et permet de choisir le format de représentation mise à disposition pour la ressource. Exemple d’un GET sur maps.google.fr avec Firefox GET Host maps.google.fr
User-Agent Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
Connection keep-alive
Referer http://news.google.fr/nwshp?hl=fr&tab=wn
@Produces, @Consumes
On accède à partir d’une unique URL à une multiplicité de représentations d’une même ressource. On utilisera les annotations @Produces et @Consumes pour gérer en entrée / sortie les multiples représentations d’une ressource.
-
@Produces : désigne le format de représentation de la ressource.
-
@Consumes : désigne le format de consommation de la méthode Java.

