Services rest & jersey

Post on 21-Jun-2015

443 views 7 download

Tags:

description

Introduction au paradigme REST et à son implémentation via le framework Jersey

Transcript of Services rest & jersey

REST & Jersey

REST ?De diou - Qu'es aquò ?

REST ?

Style d'architecture

HTTP

SOA : REST vs SOAP

Principes RESTLes 5 commandements

Aucun état tu n'aurasStateless

Historiquement avec le web, maintien de la session côté client

Aujourd'hui les clients sont capables de gérer un état de session

Adressables tes ressources serontAdressabilité

Utiliser la spécification HTTP

Une ressource = une URI

Uniforme l'accès à tes ressources sera - 1Accès via un sous ensemble des verbes HTTP

GETPUT

DELETEPOSTHEAD

Uniforme l'accès à tes ressources sera - 22 notions permettant de distinguer PUT et POST

Sûr : L’invocation d’une méthode sûre ne change pas l’état du serveur

Idempotent : signifie que le résultat d’une action sera le même quel que soit le nombre d’exécutions de cette action.

Uniforme l'accès à tes ressources sera - 3GETSur & Idempotent

Obtenir la représentation d’une ressource

Uniforme l'accès à tes ressources sera - 4PUTIdempotent

Correspond à un Create ou bien un Update

Uniforme l'accès à tes ressources sera - 5DELETEIdempotent

Supprimer une ressource du serveur

Uniforme l'accès à tes ressources sera - 6POSTNON Idempotent

Modifier une ressource du serveur. Seule opération non idempotente de la spécification HTTP

Correspond à un Create ou bien un Update

Uniforme l'accès à tes ressources sera - 7HEADSur et idempotent

Similaire à un GET, mais ne retourne pas le corps de la réponse (seulement code retour + éventuels en-têtes)

Orienté représentation tu seras

exemple :

GET sur une URI => représentation de la ressource en XML ou JSON (ou autre) suivant la phase de Content Negotiation

HATEOAS tu respecterasHypermedia As The Engine Of Application State

Navigation via des liens inclus dans la représentation des ressources

Spécification d'une ressourceMiam des specs

Contrat d'interface

Choix des ressources+

Choix des verbes+

Choix des codes retour=

Description du contrat

Et en Java ?

JSR 311JAX-RS

@Path@GET @PUT @POST @DELETE @HEAD@Produces@Consumes

Frameworks sur le marchéJersey *RESTEasyRESTLetCXF

Donc, Jersey

Jersey

Implémentation de référence de la JSR

Des fonctionnalités supplémentaires

(une prez encore mieux...)

http://matthewturland.com/slides/jersey/

Si j'avais vu ça avant j'aurai pas fait ces slides...

JerseyMise en place du projet

Dépendances maven (v1.17.1)

Attention à asm.jar (collisions dépendances Hibernate ou tout autre projet utilisant CGLIB)

http://mathieuhicauber-java.blogspot.fr/2012/12/jax-rs-jersey-on-was-61-asm-classreader.html

Jersey Contrôleurweb.xmlDéclaration dans le web.xml du package à scanner<servlet> <description>Jersey Servlet</description> <display-name>ServletContainer</display-name> <servlet-name>ServletContainer</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <!-- le package scanné par Jersey à la recherche d'annotations --> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>fr.laposte.intra.courrier.recif.rest</param-value> </init-param> ...</servlet> <!-- Le mapping d'URL voulu--><servlet-mapping> <servlet-name>ServletContainer</servlet-name> <url-pattern>/resources/*</url-pattern></servlet-mapping>

Jersey Contrôleur @Path

@Path("/artists")

public class ArtistResource {…}

... Et notre ressource est exposée !

(Comparer ça à un cycle de développement SOAP...)

@Path : Définir le chemin d'accès@[VERB] : Définir le verbe autorisé

@Path("helloWorld")@GETpublic String helloMyFriend() {...}

Jersey Contrôleur @Path @[VERB]

@PathParam : injecter un paramètre dans la signature de la méthode défini dans @Path

@Path("hello/{aName}")@GETpublic String getCustomizedHelloWorld(

@PathParam("aName") String name) {...}

Jersey Contrôleur@PathParam - 1

Possibilité d'injecter plusieurs paramètres ou de spécifier une regexp pour la partie dynamique

@Path("date/{year}-{month}-{date}") // plusieurs params

@Path("{id : \\d+}") // numériques seulement

@Path("username/{username : [a-z]+}") //alpha minuscules seulement

Jersey Contrôleur@PathParam - 2

Permet d'injecter les valeurs provenant des paramètres de requête

@Path("hello")@GETpublic String getResponseWithQueryParam(

@QueryParam("name") String nameQueryParameter) {...}

URI : http://[JAX-RS-URI]/hello?name=Mathieu

Jersey Contrôleur@QueryParam

Permet d'injecter les valeurs provenant des en-têtes de la requête HTTP

@Path("hello")@GETpublic String getResponseWithHeaderParam(

@HeaderParam("headerParam") String someHeaderParam) {...}

Jersey Contrôleur@HeaderParam

Permet d'injecter les valeurs extraites des cookies

@Path("hello")@GETpublic String getResponseWithCookieParam(

@CookieParam("cookieParam") String aParamInjectedFromCookies) {...}

Jersey Contrôleur@CookieParam

Permet d'injecter les valeurs de champs de formulaire

@Path("handleForm")@POSTpublic String handleForm(

@FormParam("username") String userName,@FormParam("password") String password) {...}

Jersey Contrôleur@FormParam - 1

Problème : avec un gros formulaire, les signatures deviennent illisibles

@Path("handleForm")@POSTpublic String handleForm(

@FormParam("value1") String value1,@FormParam("value2") String value2,@FormParam("value3") String value3,@FormParam("value4") String value4,...) {...}

Jersey Contrôleur@FormParam - 2

Jersey permet d'injecter un bean

@Path("handleForm")@POSTpublic String handleForm(

@InjectParam CustomFormValuesHandlerType form) {...}

Le type CustomFormValuesHandlerType est un POJO reprenant les valeurs du form en attribut.

Les attributs sont annotés avec @FormParam

Jersey Contrôleur@InjectParam* - 1

@Produces@Consumes

Indique le type de représentation qu'est capable de consommer ou de produire la méthode

Utilisé par le moteur Jersey en conjonction avec le header Accept envoyé par le client pour choisir la bonne méthode et le bon type de retour

Jersey ContrôleurContent Negotiation - 1

Header client : @Accept

Accept: application/json; q=1.0, application/xml; q=0.8, text/html; q=0.6, text/plain; q=0.4, text/*; q=0.2, */*; q=0.1

Jersey ContrôleurContent Negotiation - 2

Retourner une javax.ws.core.Response

@Path("/id/{artistId}") @GET @Produces({ MediaType.APPLICATION_JSON }) public Response getArtistByIdJavaxResponse (

@PathParam("artistId") Integer artistId)*throws ArtistDoesNotExistException {

Artist artist = service.getArtistById(artistId); return Response.ok().entity(artist).build(); }

Jersey ContrôleurRetourner la ressource - 1

... ou bien une entité ou liste d'entités

@Path("/id/{artistId}") @GET @Produces({ MediaType.APPLICATION_JSON }) public Artist getArtistByIdEntityResponse(

@PathParam("artistId") Integer artistId) throws ArtistDoesNotExistException {

Artist artist = service.getArtistById(artistId);

return artist; }

Jersey ContrôleurRetourner la ressource - 2

Fluent Interface idiom (ou EDL)

return Response.ok().entity(artist).header("HeaderName","headerValue").lastModified(lastModified).expires(expiresDate).build();

Jersey ContrôleurRetourner la ressource - 3

Déclaration dans le web.xml

<init-param><param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name><param-value>fr.laposte.intra.courrier.recif.rest.filters.AccreditationFilter;com.sun.jersey.api.container.filter.LoggingFilter</param-value>

</init-param>

<init-param><param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name><param-value>com.sun.jersey.api.container.filter.LoggingFilter ; fr.laposte.intra.courrier.recif.rest.filters.CORSFilter</param-value>

</init-param>

Jersey Filters - 1

Filtres de Request ou Response

Existence de filtres prédéfinis

Possibilité de créer ses filtres

Jersey Filters - 2

Permet de lancer des codes erreurs HTTP spécifique en fonction d'un type d'exception

public class ArtistDoesNotExistExceptionMapper implements ExceptionMapper<ArtistDoesNotExistException> { @Override public Response toResponse(ArtistDoesNotExistException exception) { return Response.status(Response.Status. NOT_FOUND) .entity(exception.getMessage()).type(MediaType. TEXT_PLAIN) .build(); } }

Jersey Exception mapping

Classe de support : étendre JerseyTest

@Override public WebAppDescriptor configure() { return new WebAppDescriptor.Builder("com.foo.workshops.jersey").build(); } @Override public TestContainerFactory getTestContainerFactory() { return new GrizzlyWebTestContainerFactory(); }

JerseyTUAs

Cross Origin Resource Sharing

Ajax XDomain => Interdit, mais cas fréquent dans le cadre d'une API REST

Solutions : jsonP, proxy, CORS

CORS (mode simple) : permettre au client de récupérer des ressources en Ajax provenant d'un autre domaine

JerseyCORS - 1

Requête simple (GET)

Client POST /cors HTTP/1.1Origin: http://api.bob.comHost: api.bob.com

Serveur Access-Control-Allow-Origin: http://api.bob.comAccess-Control-Expose-Headers: FooBarContent-Type: text/html; charset=utf-8

JerseyCORS - 2

Evolutions => exige une montée de version a minima si perte de compatibilité ascendente. 3 courants se dégagent :

Versioning dans l'URL

GET http://....../v1/resource/id/12345GET http://....../v2/resource/id/12345

++ Simple !- casse le principe d'unicité d'URI pour une ressource- expose un paramètre technique dans l'URI

RESTVersioning -1

Versioning via Custom Header

client Header :Version : 1.0

++ Simple-- peut poser problème derrière des proxies

RESTVersioning - 2

Versioning via Content Negotiation

http://barelyenough.org/blog/2008/05/versioning-rest-web-services

++ HATEOAS compliant-- plus complexe à mettre en oeuvre, nécessite des vendor MIME Media Types

RESTVersioning - 3