Sunteți pe pagina 1din 10

Servicii Web de tip REST

Un serviciu Web este o aplicatie software accesibil pe Internet, deci localizat la o adres
URL si accesibil prin protocolul HTTP.
REST (Representational State Transfer) nu este o nou tehnologie ci este un nou mod de a
folosi comenzile HTTP ca API pentru aplicatia client. Rezult c toate servicille REST au o
interfat uniform, pot fi mai usor extinse (sunt scalabile) si sunt mai performante fat de
serviciile care folosesc si nivelul SOAP peste HTTP.
Datele si operatiile oferite de un serviciu REST sunt considerate ca resurse, accesibile prin
adrese URI (Uniform Resource Identifiers). In serviciile REST server-ul si clientii schimb ntre
ei reprezentri ale resurselor folosind un protocol si o interfat standard (HTTP).
Resursele unei aplicatii au adrese de forma: http://host/<appcontext>/resources. Exemplu:
http://localhost:9000/customerservice/customers/123

GET obtine starea unei resurse ntr-o anumit reprezentare (uzual XML sau JSON),
POST transfer o nou stare asupra resursei (modific resursa),
PUT creeaz sau actualizeaz o nou resurs,
DELETE sterge (elimin) o resurs.

Exemplu de rspuns (xml) a o cerere GET cu adresa anterioar:

<Customer> <id>123</id> <name>John</name> </Customer>

Reprezentarea resurselor este decuplat de aceste resurse fiind accesibil n mai multe
formate (text, HTML,XML,PDF, JPEG, s.a). Un client poate cere un anumit format al rspunsului
prin protocolul HTTP (Content Negociation).
Interactiunile clientului cu resursele sunt stateless si orice modificare de stare este transmis
n mod explicit prin una din metodele urmtoare: rescriere URI, cookies, cmpuri ascunse.
Cererile de tip PUT si POST pot contine date, sub forma de documente XML, iar rspunsul
serviciului la orice fel de cerere are tot forma unui document XML (sau JSON). Clientul trebuie
s poat prelucra rspunsurile XML si s genereze documentele XML continute n cereri.
Clientul unui serviciu REST trebuie s cunoasc detaliile operatiilor oferite de acest serviciu,
fie printr-o documentatie de utilizare (eventual sub forma unei pagini HTML), fie printr-un fisier
ce poate fi prelucrat de programul client, asemntor cu fisierul WSDL de la serviciile SOAP.
A fost propus un limbaj bazat pe XML pentru descrierea de servicii REST, numit WADL (Web
Application Description Language), utilizat de implementarea Jersey si de SoapUI.
Printre avantajele serviciilor REST este si forma mai compact a cererilor de servicii obtinut
prin eliminarea mesajelor SOAP peste HTTP. Exemplu comparativ:

POST /purchase_orders HTTP/1.1 Host: accounting.mycompany.com


content-type: application/purchase-order+xml
....
<po>...</po>

POST /generic_message_handler
content-type: application/SOAP+XML
<soap:envelope>
<soap:body>
<submit-purchase-order>
<destination>accounting.mycompany.com</destination>
<po>...</po>
</submit-purchase-order>
</soap:body>
<soap:envelope>

Implementri REST
1
Instrumentele pentru implementri de servicii REST pot fi clasificate astfel:
- Instrumente pentru crearea de furnizori si clienti de servicii de orice fel;
- Instrumente pentru crearea de clienti la servicii existente (Google, Amazon, Yahoo, Atom, s.a.)
Ca si n cazul serviciilor Web de tip SOAP implementarea unui serviciu are dou prti:
- Crearea unui furnizor de servicii, care nseamn pentru REST definirea unor metode care
rspund la diverse cereri GET, POST sau PUT (mai rar DELETE);
- Crearea unui client, care s compun si s trimit cereri HTTP acceptate de furnizorul de
servicii. Clientul este de obicei parte din aplicatia care foloseste serviciul dar poate fi si un utilitar
cum este cURL care poate genera cereri HTTP sau un produs mai complex ca SoapUI.
Furnizorul de servicii REST poate fi implementat ntr-un server JavaEE fie:
- Printr-un servlet dispecer care foloseste la rndul lui alte clase scrise manual si/sau generate
de framework.
- Printr-o component EJB la care se adaug o fatad de serviciu Web.
Exist diferite niveluri de programare a furnizorilor si clientilor de servicii Web, care folosesc
diferite biblioteci sau infrastructuri de tip framework pentru simplificarea operatiilor. Nivelul cel
mai cobort este utilizarea de clase JDK (din Java SE) iar nivelul cel mai ridicat este JAX-RS.
Pentru generarea de cereri HTTP se pot folosi clase JDK (HttpURLConnection) sau clase
ApacheHTTPClient.
Exemplu de metod Java care creeaz un sir (obiect String) cu continutul unei cereri GET
folosind numai clase JDK:

public static String httpGet(String urlStr) throws IOException {


URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
if (conn.getResponseCode() != 200) {
throw new IOException (conn.getResponseMessage()); }
BufferedReader rd = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
sb.append(line); }
rd.close();
conn.disconnect();
return sb.toString();
}

Bibliotecile de clase si adnotrile simplific asocierea unor clase Java obisnuite (POJO) cu
cererile HTTP (ceea ce se numeste HTTP Bindings). In plus, ca si n cazul serviciilor SOAP, se
poate creea o interfat cu metodele oferite de serviciu (SEI=Service Endpoint Interface).
Exemplu de interfat pentru un serviciu CXF (din exemplul restful_http_binding):

@WebService(targetNamespace = "http://demo.restful.server")
public interface CustomerService {

@Get
@HttpResource(location = "/customers")
@WebResult(name = "Customers")
Customers getCustomers();
@Get
@HttpResource(location = "/customers/{id}")
Customer getCustomer(@WebParam(name = "GetCustomer")
GetCustomer getCustomer) throws CustomerNotFoundFault;
@Put
@HttpResource(location = "/customers/{id}")
void updateCustomer(@WebParam(name = "Customer")

2
Customer c);
@Post
@HttpResource(location = "/customers")
long addCustomer(@WebParam(name = "Customer")
Customer c);
@Delete
@HttpResource(location = "/customers/{id}")
void deleteCustomer(@WebParam(name = "id")
long id) throws CustomerNotFoundFault;
}

Exemplu de implementare a interfetei, din acelasi exemplu:

@WebService(endpointInterface = "demo.restful.server.CustomerService")
public class CustomerServiceImpl implements CustomerService {
long currentId = 1;
Map<Long, Customer> customers = new HashMap<Long, Customer>();
public CustomerServiceImpl() {
Customer customer = createCustomer();
customers.put(customer.getId(), customer);
}
public Customers getCustomers() {
Customers c = new Customers();
c.setCustomer(customers.values());
return c;
}
public Customer getCustomer(GetCustomer getCustomer) throws CustomerNotFoundFault {
Customer c = customers.get(getCustomer.getId());
if (c == null) {
CustomerNotFoundDetails details = new CustomerNotFoundDetails();
details.setId(getCustomer.getId());
throw new CustomerNotFoundFault(details);
}
return c;
}
public void updateCustomer(Customer c) {
customers.put(c.getId(), c);
}
public long addCustomer(Customer c) {
long id = ++currentId;
c.setId(id);
customers.put(id, c);
return c.getId();
}
public void deleteCustomer(long id) {
customers.remove(id);
}
final Customer createCustomer() {
Customer c = new Customer();
c.setName("John");
c.setId(123);
return c;
}
}

Exemplu de client al serviciului anterior:

public final class Client {


private Client() { }
public static void main(String[] args) throws Exception {

3
// Sent HTTP GET request to query customer info
System.out.println("Sent HTTP GET request to query customer info");
URL url = new URL("http://localhost:8080/xml/customers");
InputStream in = url.openStream();
System.out.println(getStringFromInputStream(in));
}
private static String getStringFromInputStream(InputStream in) throws Exception {
return IOUtils.toString(in);
}
}
Alte operatii ale serviciului pot fi testate introducnd urmtoarele adrese de resurse fie direct
ntr-un browser, fir prin CURL:

http://localhost:8080/xml/customers [ lista cu toti clientii in xml ]


http://localhost:8080/json/customers [ lista cu toti clientii in json ]
http://localhost:8080/xml/customers/123 [ nume client cu codul 123 in xml]
http://localhost:8080/json/customers/123

Rspunsurile la aceste cereri sunt mici fisiere XML sau JSON de forma urmtoare:

<?xml version="1.0" encoding="UTF-8"?>


<customer xmlns="http://demo.restful.server">
<name>Jim</name>
</customer>

{ "acme.Customer" : { "acme.name" : "Jim" } }

Exemplu de fisier XML trimis cu POST pentru modificare nume client cu codul 123:

<?xml version="1.0" encoding="UTF-8"?>


<customer xmlns="http://demo.restful.server">
<id>123</id>
<name>Danno</name>
</customer>

Implementrile de servicii Web REST s-au modificat rapid n ultimii ani, influentate mai ales
de aparitia adnotrilor Java si a standardului JAX-RS. In prezent este posibil crearea si
utilizarea de servicii REST cu sau fr adnotri.
Cele mai importante implementri de JAX-RS sunt:
- Jersey : este cea mai nou implementare de referint de la Oracle (Sun) si nlocuieste
implementrile de referint anterioare numite Metro. Metro exist nc si este asociat cu
Glassfish, dar poate fi folosit si cu Tomcat.
- CXF : este o implementare Apache, cu multe exemple care include crearea unui mic server
astfel c utilizarea lor este mai simpl.

JAX-RS (JSR 311)

JAX-RS este un API Java pentru crearea de servicii Web de tip REST, parte din JEE6,definit
n JSR 311 si care defineste n principal o serie de adnotri Java utilizabile pentru acest tip de
servicii. In cadrul acestui standard resursele sunt clase Java obisnuite (POJO=Plain Old Java
Objects) care sunt fie adnotate cu @Path, fie au cel putin o metod adnotat cu @Path sau cu
o adnotare ce specific metoda HTTP folosit ntr-o cerere: @GET, @PUT, @POST,
@DELETE. Acestea sunt metodele resursei si vor prelucra cererile corespunztoare adnotrii
lor; deci o metod @GET va prelucra o cerere GET iar rspunsul depinde si de parametri
acestei cereri. Altfel spus, adnotrile realizeaz asocierile dintre metodele clasei si cererile
HTTP.
Adnotrile JAX-RS genereaz clasele Java care prelucreaz cererile HTTP primite.

4
JAX-RS este un API numai pentru furnizorii de servicii REST, nu si pentru clientii REST.
NetBeans poate genera clase resurse si permite testarea de servicii Web de tip REST.
O clas resurs este o clas Java cu adnotrile JAX-RS necesare pentru a fi o resurs.
Scheletul unei clse resursarat astfel:

@Path("/customerservice/")
@Produces("application/xml")
public class CustomerService {
public CustomerService() { }
@GET
public Customers getCustomers() { .... }
@GET
@Path("/customers/{id}")
@Produces("application/json")
public Customer getCustomer(@PathParam("id") String id) { ... }
@PUT
@Path("/customers/{id}")
@Consumes("application/xml")
public Response updateCustomer(@PathParam("id") Long id, Customer customer) { .... }
@POST
@Path("/customers")
public Response addCustomer(Customer customer) { .... }
@DELETE
@Path("/customers/{id}/")
public Response deleteCustomer(@PathParam("id") String id) { .... }
@Path("/orders/{orderId}/")
public Order getOrder(@PathParam("orderId") String orderId) { .... }
}

@Path specific o cale relativ URI, care poate include si variabile (URI path templates).
@Produces specific formatul MIME al rspunsului produs de metod ca reprezentare a strii
resursei.
@Consumes specific formatul MIME al reprezentrii resursei trimise de client si primit de o
metod care consum acest format. Exemplu:

@POST
@Consumes("text/plain")
public void postMessage(String message) {
// Store the message
}

Calea relativ @Path se adaug la adresa URI a serviciului (unde este instalat pe server) si
este prelucrat de un servlet. De exemplu, o resurs are adresa URI: http://example.com, iar
calea relativ foloseste o variabil username ntre acolade:
@Path("/users/{username}")
Dac utilizatorul introduce pentru nume sirul restuser atunci serviciul Web va rspunde la :
http://example.com/users/restuser

Numele introdus n formular si primit n variabila username si poate fi folosit astfel n cadrul
unei metode:

@Path("/users/{username}")
public class UserResource {
@GET
@Produces("text/xml")
public String getUser(@PathParam("username") String userName) {
...
}
}
5
Calea relativ URI poate contine mai multe variabile. Exemplu:

@Path("/{name1}/{name2}/")
public class SomeResource {
...
}

Calea absolut este un sablon de cale (path template) de forma:


http://example.com/myContextRoot/resources/{name1}/{name2}/

Calea relativ poate avea sau nu la nceput si la sfrsit caractere /.


Metodele Java adnotate pot avea ca rezultat un tip Java sau javax.ws.rs.core.Response;
obiectul Response poate fi creat cu un ResponseBuilder.
Extragerea parametrilor dintr-o cerere HTTP se face folosind adnotarea @QueryParam.
Fisierele XML cu date transmise de POST sau PUT sau cu rspuns la GET pot fi generate cu
JAXB din clase Java (data binding), ca n exemplul urmtor:

// clasa ptr clienti


@XmlRootElement(name = "Customer")
public class Customer {
private String name;
private long id;
public void setName(String n) {name = n; }
public String getName() {return name; }
public void setId(long i) { id = i; }
public long getId() { return id; }
}

// raspuns la GET
@Path("/customerservice/")
public class CustomerService {
@GET
@Path("/customers/{customerId}/")
public Customer getCustomer(@PathParam("customerId") String id) {
....
}
}

Exemplu de document XML transmis de serviciu ctre client:

<Customer>
<id>123</id>
<name>John</name>
</Customer>

Implementarea de referint Jersey

Jersey permite implementarea de servicii JAX-RS si de clienti pentru aceste servicii cu un


effort de programare minim si fr a se lega de un anumit server, prin utilizarea unui numr
mare de biblioteci proprii si de la alti furnizori. Deoarece construirea de servcii si clienti cu
Jersey prezint multe dependente, exemplele care nsotesc implementarea sunt proiecte
Maven (fisiere de build de tip pom.xml), iar executarea lor (pentru prima dat) necesit un
timp considerabil pentru descrcarea din depozitul Maven a acestor dependente.
Crearea unui serviciu cu Jersey seamn cu crearea altor servicii ce respect JAX-RS.
Exemplu:

6
package jersey.first;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
// POJO, no interface no extends
//Sets the path to base URL + /hello
@Path("/hello")
public class Hello {
// This method is called if TEXT_PLAIN is request
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayPlainTextHello() {
return "Hello Jersey";
}
// This method is called if XMLis request
@GET
@Produces(MediaType.TEXT_XML)
public String sayXMLHello() {
return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";
}
// This method is called if HTML is request
@GET
@Produces(MediaType.TEXT_HTML)
public String sayHtmlHello() {
return "<html> " + "<title>" + "Hello Jersey" + "</title>"
+ "<body><h1>" + "Hello Jersey" + "</body></h1>" + "</html> ";
}
}

Fisierul web.xml trebuie creat/modificat astfel ca s includ Jersey ca servlet dispecer:

<display-name>jersey.first</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>jersey.first</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

Pentru a verifica versiunea text se poate folosi utilitarul cURL astfel:


curl http://localhost:8080/jersey.first/rest/hello

La crearea unui client cu Jersey se refolosesc o parte din clasele folosite la crearea
serviciului ( UriBuilder, UriTemplate, clase MIME Multipart s.a.) plus alte clase noi cum este
WebResource, ale crei metode se apeleaz pentru generarea de cereri HTTP. Exemplu de
client la serviciul creat anterior:

package jersey.first.client;

7
import java.net.URI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
public class Test {
public static void main(String[ ] args) {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(getBaseURI());
// Fluent interfaces
System.out.println(service.path("rest").path("hello").accept(
MediaType.TEXT_PLAIN).get(ClientResponse.class).toString());
// Get plain text
System.out.println(service.path("rest").path("hello").accept(
MediaType.TEXT_PLAIN).get(String.class));
// Get XML
System.out.println(service.path("rest").path("hello").accept(
MediaType.TEXT_XML).get(String.class));
// The HTML
System.out.println(service.path("rest").path("hello").accept(
MediaType.TEXT_HTML).get(String.class));
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/jersey.first").build();
}
}

Exemplul urmtor foloseste JAXB pentru crearea de documente XML (JSON) din clase Java:

// clasa transformata in document XML


package jersey.jaxb.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
// JAX-RS supports an automatic mapping from JAXB annotated class to XML and JSON
public class Todo {
private String summary;
private String description;
public String getSummary() {return summary;}
public void setSummary(String summary) { this.summary = summary;}
public String getDescription() {return description; }
public void setDescription(String description) { this.description = description;}
}
// clasa resurs JAX-RS
package jersey.jaxb;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import jersey.jaxb.model.Todo;
@Path("/todo")
public class TodoResource {
// This method is called if XMLis request
@GET
@Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Todo getXML() {
Todo todo = new Todo();
todo.setSummary("This is my first todo");
todo.setDescription("This is my first todo");
return todo;
8
}
// This can be used to test the integration with the browser
@GET
@Produces( { MediaType.TEXT_XML })
public Todo getHTML() {
Todo todo = new Todo();
todo.setSummary("This is my first todo");
todo.setDescription("This is my first todo");
return todo;
}
}
// clasa client
package jersey.jaxb.client;
import java.net.URI;
import javax.ws.rs.core.*;
import com.sun.jersey.api.client.*;
import com.sun.jersey.api.client.config.*;
public class Test {
public static void main(String[] args) {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(getBaseURI());
// Get XML
System.out.println(service.path("rest").path("todo").accept(
MediaType.TEXT_XML).get(String.class));
// Get XML for application
System.out.println(service.path("rest").path("todo").accept(
MediaType.APPLICATION_JSON).get(String.class));
// Get JSON for application
System.out.println(service.path("rest").path("todo").accept(
MediaType.APPLICATION_XML).get(String.class));
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/jersey.jaxb").build();
}
}

Servicii REST cu SoapUI

SoapUI a fost extins (fat de versiunile initiale) pentru exersarea si testarea de servicii Web
REST prin generarea unui client al serviciului care ruleaz ntr-o interfat grafic (UI).
Clientul REST este generat fie pe baza unei adrese URL de endpoint (unde este expus o
interfat a serviciului), fie pe baza unei descrieri a serviciului n XML (WADL=Web Application
Description Language).Soap UI poate genera WADL si foloseste modelul creat de WADL.
In cadrul acestui model serviciile REST implic urmtoarele elemente:
- Servicii (Services) corespund interfetelor din WSDL; n WADL corespund elementului root
al aplicatiei. Un serviciu contine un numr oarecare de resurse, organizate ierarhic.
- Resurse (Resources) corespund elementelor adresabile printr-un URI, accesibile prin
metode standard HTTP (GET,PUT,..) si care pot fi fcute accesibile n mai multe reprezentri
(XML,JSON,PDF,s.a.)
- Metode (Methods) de acces la resurse; o metod este definit printr-o cerere HTTP, antete
(headers) si parametri. Rspunsul unei metode este o reprezentare a resursei.
- Cereri (Requests) sunt instante ale metodelor, cu valori pentru parametri acestora.
- Parametri, pot fi de mai multe feluri: QUERY = adugati sirului cerere HTTP (query string),
HEADER = inclusi n antetul HTTP, TEMPLATE si MATRIX.
- Reprezentri , care definesc continutul cererilor si al rspunsurilor.
SoapUI are un Help extins, cu exemple, pentru generarea de clienti, de cereri si de fisiere
WADL pentru diferite servicii REST.

9
BIBLIOGRAFIE

Oracle : The Java EE 6 Tutorial (2010)


Ch.11: Introduction to WebServices
Ch.13: Building RESTful Web Services with JAX-RS and Jersey

10

S-ar putea să vă placă și