Vous êtes sur la page 1sur 6

Desenvolvendo WS

no estilo REST

Este documento descreve como criar um servio Web (WS) que segue o estilo REST.
Cabe salientar que tais servios so comumente chamados de WS RESTful. Como nos
tutoriais anteriores, utilizaremos tcnicas e ferramentas de baixo nvel, antes de
passarmos para um ambiente de desenvolvimento.
O que significa REST?
Como j havamos estudado, SOAP o protocolo utilizado pelos servios Web para
trocar mensagens que carregam dados de entrada e de sada para os WS. REST, por
outro lado, um estilo de arquitetura de software para o desenvolvimento de sistemas
hipermdia, ou seja, aplicaes que envolvem vrios tipos de mdia (como texto,
imagem, udio, etc.), armazenadas em uma rede e interconectadas por hiperlinks
(KALIN, 2009). Podemos utilizar essa mesma ideia para servios Web, j que eles
funcionam em cima da Web, ou seja, usam o HTTP, e possuem URI prprias, podendo
inclusive estar interconectados.
Cabe salientar que o HTTP funciona tanto como protocolo de transporte quanto como
um sistema de troca de mensagens, j que as requisies e as respostas usadas no
HTTP so, efetivamente, mensagens. O HTTP, inclusive, informa quando uma
requisio ocorreu com sucesso ou no.
Como na abordagem REST tudo aquilo que possui uma URI considerado um recurso e
WS possuem URI prprias, podemos us-la para o desenvolvimento de aplicaes
baseadas em WS.
Na prtica, um recurso um item informacional que possui hiperlinks para ele. Os
hiperlinks usam URI como base para fazer a ligao entre dois recursos. Na Web, os
itens informacionais no fazem sentido se eles no tiverem uma representao. As
pginas Web, por exemplo, so representadas por textos no formato HTML (i.e.,
possuem o tipo text/html). Os recursos, porm, podem ter mais de uma
representao. Alm do mais, os recursos possuem estado. Por exemplo, um jogador
de futebol pode estar alocado em um time em um ano, mas mudar para outro no ano
seguinte. Uma representao de recurso deve capturar o estado de um recurso.
Quando usamos a abordagem REST, uma requisio tem como alvo um recurso. Quem
requisita o recurso recebe uma representao de tal recurso, caso a requisio ocorra
com sucesso, mas o recurso em si continua no servidor. a representao do recurso
que transferida do servidor para o cliente (por isso o nome da abordagem REST,
REpresentation State Transfer, que em portugus significa algo como Transferncia de
Estado de Representao). Uma representao s adequada se consegue capturar o
estado do recurso de maneira apropriada (KALIN, 2009).
Ainda, segundo Kalin (2009), WS RESTful no s requerem que os recursos
representem estados, mas tambm que suportem operaes a serem invocadas por
clientes. Tais operaes esto diretamente relacionadas com as operaes ou mtodos
que o HTTP oferece, que so POST, GET, PUT e DELETE. Para quem trabalha com
aplicaes Web, tais verbos so familiares. Esses mtodos (ou verbos) esto
normalmente relacionados com as operaes chamadas na computao de CRUD
(Create, Read, Update, Delete), que significam, respectivamente, Criar, Ler, Atualizar e
Apagar um recurso. No caso dos WS RESTful, portanto, POST usado para criar, GET
para ler, PUT para atualizar e DELETE para apagar um recurso.
Com isso, sempre que um cliente desejar invocar um servio, ele deve utilizar uma URL
que indique onde o servio est (sua URI) e a operao que deseja realizar (uma das
anteriores). O servio deve interpretar a requisio, com base no que lhe passado
pelo protocolo HTTP, e executar a tarefa solicitada. Nada disso impede, seja o cliente
ou o WS, de utilizarem SOAP para representar suas entradas e sadas. No entanto,
normalmente eles utilizam uma maneira mais simples para isso o sistema de tipos
MIME, por exemplo, que suportado pelo HTTP. O estado de um WS , ento,
transferido via uma mensagem de resposta HTTP.
Sendo assim, quando estamos lidando com WS RESTful, devemos utilizar os verbos
HTTP para especificar as aes que devem ser realizadas em um WS (representado por
sua URI). Levando em conta que o protocolo HTTP permite a especificao de
parmetros a serem passados em uma URL, os seguintes comandos poderiam ser
dados a um WS RESTful que representasse os alunos de uma universidade:
POST aluno Cria um novo aluno
GET aluno?id=00214234 recupera dados do aluno de cdigo 00214234
DELETE aluno?id=00221223 apaga o aluno cujo cdigo 00221223
Criando um WS RESTful
Em Java, se usarmos a anotao @WebServiceProvider ao invs da anotao
@WebService, o compilador saber que no estamos mais usando SOAP, mas sim que
o servio processa XML de algum tipo. Servios do tipo REST retornam mensagens em
XML puro, mas no precisam receber requisies em XML (como j vimos).
Se voc j desenvolveu aplicaes Web, deve ter visto que uma requisio do tipo GET
no possui corpo, mas a prpria URL composta de variveis e argumentos (atributos)
que indicam os parmetros desejados de uma string de consulta.
A ttulo de exemplo, analise a seguinte URL (fictcia):
http://svx.com/disciplinas?curso=computacao&ano=2013.
Em tal URL, o smbolo de interrogao indica o incio da string de consulta, e os pares
de atributo e valor so separados pelo smbolo &. No exemplo, o servio
disponibilizado na URL http://svx.com retornaria todas as disciplinas cujo curso
igual a computao e que so oferecidas no ano de 2013.
Outra coisa que muda em um servio RESTful que a anotao
@WebServiceProvider obriga a classe a implementar o mtodo invoque da
interface Provider. Tal mtodo possui a seguinte assinatura:
public Source invoke(Source request)
Percebe-se que ele espera uma fonte de bytes (i.e., uma Source), a qual um
documento XML (ou no) que representa a requisio, e retorna uma Source de
bytes que contm a resposta XML.
O cdigo seguinte
1
implementa um servio REST. Ele mais completo e complexo do
que o anterior, pois implementa uma interface de provedor genrico (ao contrrio do
outro, que era focada em webmethods especficos).
package time;

import javax.xml.ws.Provider;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.annotation.Resource;
import javax.xml.ws.BindingType;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.http.HTTPException;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.http.HTTPBinding;
import java.beans.XMLEncoder;
import java.beans.XMLDecoder;
import java.util.*;
import java.io.*;

@WebServiceProvider
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE)
@BindingType(value = HTTPBinding.HTTP_BINDING)
public class TimesRESTFull implements Provider<Source> {
@Resource

1
Esse cdigo e os demais foram adaptados de Kalin (2009).
protected WebServiceContext ws_ctx;

private Map<String, Time> team_map;
private List<Time> teams;
private byte[] team_bytes;
private static final String file_name = "times.ser";

public RestfulTeams() {
read_teams_from_file();
deserialize();
}

public Source invoke(Source request) {
if(ws_ctx==null) throw new RuntimeException("Falha!");
MessageContext msg_ctx = ws_ctx.getMessageContext();
String http_verb = (String)
msg_ctx.get(MessageContext.HTTP_REQUEST_METHOD);
http_verb = http_verb.trim().toUpperCase();
if(http_verb.equals("GET")) return doGet(msg_ctx);
else throw new HTTPException(405);
}

private Source doGet(MessageContext msg_ctx) {
// Analisa a string de consulta
String query_string = (String)
msg_ctx.get(MessageContext.QUERY_STRING);
if(query_string == null){
return new StreamSource(
new ByteArrayInputStream(team_bytes));
}else {
String name = get_value_from_qs("name", query_string);
Time team = team_map.get(name);
if (team == null) throw new HTTPException(404);
ByteArrayInputStream stream = encode_to_stream(team);
return new StreamSource(stream);
}
}
private ByteArrayInputStream encode_to_stream(Object obj) {
// Serializa objeto em formato XML
ByteArrayOutputStream stream =
new ByteArrayOutputStream();
XMLEncoder enc = new XMLEncoder(stream);
enc.writeObject(obj);
enc.close();
return new ByteArrayInputStream(stream.toByteArray());
}
private String get_value_from_qs(String key, String qs) {
String[ ] parts = qs.split("=");
if(!parts[0].equalsIgnoreCase(key))
throw new HTTPException(400); // requisio incorreta
return parts[1].trim();
}

private void read_teams_from_file() {
try {
String cwd = System.getProperty ("user.dir");
String sep = System.getProperty ("file.separator");
String path = get_file_path();
int len = (int) new File(path).length();
team_bytes = new byte[len];
new FileInputStream(path).read(team_bytes);
}catch(IOException e) { System.err.println(e); }
}

private void deserialize() {
// Des-serializa a partir do arquivo
XMLDecoder dec = new XMLDecoder(
new ByteArrayInputStream(team_bytes));
teams = (List<Time>) dec.readObject();
team_map = Collections.synchronizedMap(
new HashMap<String, Time>());
for (Time team : teams)
team_map.put(team.getName(), team);
}

private String get_file_path() {
String cwd = System.getProperty ("user.dir");
String sep = System.getProperty ("file.separator");
return cwd + sep + "time" + sep + file_name;
}
}
No se preocupe se voc no entender o cdigo anterior. O mais importante saber
que o ele faz definir um WS que recupera informaes sobre times de futebol. Alm
disso, a parte que nos interessa a parte destacada em negrito.
Verifique que, logo antes da definio da classe principal, voc encontra as seguintes
anotaes:
@WebServiceProvider: indica que o servio implementa uma interface mais
genrica de provedor. Tal interface no usa SOAP para processar mensagens,
mas sim XML como base, permitindo que as mensagens sejam manipuladas
pelo prprio servio. Servios REST usam tal anotao (em Java).
@ServiceMode(value = javax.xml.ws.Service.Mode.MESSAGE): indi-
ca o modo do servio (service mode). H dois valores vlidos para o service
mode. O padro o modo PAYLOAD, que indica que o servio acessa somente o
corpo de uma requisio HTTP do tipo POST. O modo MESSAGE, que o usado
no exemplo, indica que o servio quer processar toda a mensagem HTTP (i.e.,
seu corpo e o seu cabealho).
@BindingType(value = HTTPBinding.HTTP_BINDING): indica que o
servio utilizar HTTP ao invs de SOAP.
Toda vez que o servio for chamado, o mtodo invoke(Source request)
executado. Ele processa a mensagem em HTTP recebida pelo servio e devolve um
resultado. Analise o mtodo invoke do exemplo e perceba que o servio
implementado somente processa requisies do tipo GET, gerando excees para
todos os outros casos. Num caso real, provavelmente fosse necessrio processar os
demais tipos de verbos (incluso, atualizao e excluso).
Referncias
Kalin, Martin. Java Web Services: Up and Running. Sebastopol, CA: OReilly. 318p.
2009.

Vous aimerez peut-être aussi