RESTful Web Services sunt servicii web bazate pe metodele HTTP și conceptul de REST. De obicei următoare patru metode HTTP sunt folosite în definirea serviciilor RESTful:
Conceptul de REST a fost introdus pentru prima dată în 2000, de Roy Fielding. Mai jos sunt câteva aspecte importante legate de REST:
Un serviciu RESTful definește, în mod tipic, URI-ul de bază (de exemplu: http://myserver.com/myresources), MIME-typurile pe care le consumă/produce (de exemplu: JSON, XML, definit de user, etc) și operațiile asociate (prezentate anterior).
În Java, suportul pentru servicii RESTful se numește Java API for Restful Web Services (JAX-RS) și este definit de JSR 311. JAX-RS se bazează foarte multe pe annotations după cum se va vedea în exemplul de mai jos. Jersey este o implementare open source a JAX-RS, care are calitate de producție și pe care am folosit-o în proiectele mele. Exemplul de mai jos a fost implementat folosind Jersey. De menționat că JAXB este folosit pentru suportul de JSON și XML al JAX-RS. Alte implementări ar fi: Apache CXF, Restlet, JBOss RESTEasy.
Să încercăm să construim o mică aplicație folosind Jersey. Aplicația va oferi o interfață pentru managementul unei resurse numite "books". Totodată voi prezentă o modalitate de a folosi serviciul Web creat, folosind suportul de client oferit to de Jersey.
Partea de server va expune o serie de metode folositoare în a administra resursa "books": reset, get, list, delete și add.
Partea de client va fi creată sub forma unui JUnit și va expune o serie de metode de test pentru a valida funcționalitatea serviciul Web.
Proiectul a fost implementat folosind SpringSource Tool Suite (incluzând Web Serverul WMware vFabric), openJDK 7 si Maven 3 pe Ubuntu 12. Jersey are nevoie de patru librarii (și dependințele acestora):
Folosirea Jersey client împreună cu Jersey server nu este o cerință absolută conform definiției Restful WebServices (s-a folosit abordarea aceasta doar pentru a exemplifica mai multe aspecte ale Jersey).
Maven oferă o modalitate built-in de rezolvare a dependințelor acestor librării deci este recomandată folosirea acestui tool. Pentru detalii, vezi: https://github.com/tavibolog/TodaySoftMag/blob/master/pom.xml .
Orice aplicația care va fi instalată într-un container de tip servlet va avea nevoie de un fisier web.xml de configurare. Aici se va specifica servlet-ul de care Jersey are nevoie pentru a se inițializa și totodată calea spre serviciile Restful oferite, se specifică pachetul Java ca valoare a parametrului com.sun.jersey.config.property.packages:
Jersey REST Service
com.sun.jersey.spi.container.servlet.ServletContainer
com.sun.jersey.config.property.packages
com.todaysoftmag.examples.rest
1
Jersey REST Service
Servlet mapping specifică pattern-ul de URL pe care se va apela servlet-ul Jersey. Pentru un URL de forma:
http://
maparea se referă la
http://
Dacă în URL pattern folosim de examplu "/home", atunci requestul va fi de genul:
http://
Clasa domeniu definește structura obiectelor folosite de către serviciile Web. În principiu clasele domeniu sunt POJO.
Annotările @XmlRootElement și @XmlElement sunt necesare pentru ca JAXB să poată fi folosit să mapeze automat date în formate XML sau JSON la POJO și vice-versa. Acest support este oferit de către JAX-RS. În cazul în care clasa domain (Book în cazul nostru) definește un constructor, atunci și constructorul default trebuie definit, el fiind folosit de JAXB în procesul de mapare.
@XmlRootElement
public class Book {
@XmlElement(name = "id")
String id;
@XmlElement(name = "name")
String name;
@XmlElement(name = "author")
String author;
…
}
Codul complet al clasei domeniu este aici: https://github.com/tavibolog/TodaySoftMag/blob/master/src/main/java/com/todaysoftmag/examples/rest/Book.java.
După cum am menționat anterior, JAX-RS folosește din plin annotări. Majoritatea annotărilor se găsesc în pachetele: javax.ws.rs.* și javax.ws.rs.code.* din dependința jersey-core. Să încercăm să le discutăm pe cele mai importante.
Pentru definirea serviciului este suficient să definim o clasă care se află în pachetul Java definit în web.xml de parametrul com.sun.jersey.config.property.packages. În cazul nostru va fi com.todaysoftmag.examples.rest.
package com.todaysoftmag.examples.rest;
// importurile sunt omise
@Path("/books")
public class BookService {
…
}
După cum observați definiția clasei este precedată de o annotare: @Path. Aceasta definește calea spre serviciul Web. Dacă folosim exemplu de mai sus, URL-ul va fi:
http://
De asemenea annotarea @Path este folosită și la nivelul metodelor expuse de serviciul Web:
@PUT
@Path("/add")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Book add(Book book) {
….
}
În acest caz, valoarea definită in annotare se va adăuga ca parte a URL-ul serviciului pentru metoda respectivă. În cazul nostru, pentru a adăuga o "carte", URL-ul va fi:
http://
Această metodă mai este precedată de o serie de annotări:
Există cazuri în care dorim să trimitem parametri ca și parte a URL-ului de request. JAX-RS definește o serie de annotări care pot fi folosite în aceste sens. Cele mai uzuale sunt:
@DELETE
@Path("/delete/{id}")
public Book delete(@PathParam("id") String id) {
…
}
@GET
@Path("/list")
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
public Book[] list(@QueryParam("s") @DefaultValue("") String search) {
…
}
@POST
@Path("/reset")
public Response reset(@HeaderParam("clearOnly") boolean clearOnly , @CookieParam("credentials") String credentialsȘ) {
…
}
Codul complet al serviciului "Books" este aici: https://github.com/tavibolog/TodaySoftMag/blob/master/src/main/java/com/todaysoftmag/examples/rest/BookService.java
Există diferite modalități de implementare a unui client rest: folosind pagini HTML, folosing Apache HTTP Client, folosing Jersey Client, etc. in acest articol se va prezenta folosirea clientului Jersey.
Configurarea unui client Jersey se face folosind interfața com.sun.jersey.api.client.config.ClientConfig. Configurarea clientului se referă la nume de proprietăți, funcționalități, etc. care vor putea fi folosite de către clientul Jersey. Jersey oferă o implementare default a interfeței, numită DefaultClientConfig. O inițializare a configurării clientul Jersey este foarte simplă:
ClientConfig config = new DefaultClient
Config();
Pasul următor este crearea clientului Jersey (clasa com.sun.jersey.api.client.Client). Este important de reținut că această operație este foarte costisitoare și necesită resurse considerabile. De aceea este recomdată refolosirea unui client Jersey.
Client client = Client.create(config);
Odată ce avem clientul Jersey va trebui să ne creăm un obiect WebResource (clasa com.sun.jersey.api.client.WebResource). Acesta ne va permite să executăm request-uri înspre metodele unui serviciu Web, oferind totodată capabilități de procesare a răspunsurilor.
WebResource resource = client.
resource(UriBuilder.fromUri("http://localhost:7000/TodaySoftMag").build());
Odată avut obiectul WebResource putem începe să îl folosim pentru a trimite request-uri. Veți identifica în exemplele de mai jos și folosirea patternul-ui Builder folosit pentru crearea request-urilor.
Să luam următorul exemplu de request și să îl explicăm:
Book book = resource.path("/books").path("/list").accept(MediaType.TEXT_HTML).get(Book.class);
Mai multe exemple găsiți în unit testul proiectului: https://github.com/tavibolog/TodaySoftMag/blob/master/src/test/java/com/todaysoftmag/examples/rest/BookServiceTest.java . Exemplele folosesc metodele WebResource prezentate mai sus, plus următoarele:
În concluzie, consider că folosirea Jersey ca framework de dezvoltare și testare a serviciilor Restful este ușor de aprofundat, oferind developerilor un set extins de functionalități pentru dezvoltarea aplicațiilor.
http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
http://en.wikipedia.org/wiki/REST
http://jcp.org/aboutJava/communityprocess/final/jsr311/index.html
de Radu Popescu
de Ionel Mihali