Aplicando Web Services Rest Com a API Jax Rs

20

Click here to load reader

Transcript of Aplicando Web Services Rest Com a API Jax Rs

Page 1: Aplicando Web Services Rest Com a API Jax Rs

Aplicando Web Services REST com a API JAX-RS

Rodrigo Araújo dos SantosEdigar A. Diniz Júnior

Resumo

Este artigo visa apresentar a tecnologia REST que representa uma alternativa ao desenvolvimento de Web Services SOAP. Será apresentada também a API JAX-RS, que facilita o desenvolvimento de aplicações REST que utilizam a linguagem Java. Adicionalmente, será desenvolvida uma aplicação que demonstre como projetar uma aplicação REST com a linguagem Java e a API JAX-RS.

Palavras-chave: REST, Web Services, API JAX-RS, SOAP, JAVA

1. Introdução

Os Web Services surgiram como uma forma de comunicação entre aplicações distribuídas e heterogêneas. Entretanto ao desenvolver uma aplicação que necessite disponibilizar Serviços Web (citados neste artigo como Web Services), tem-se duas opções de implementação para tal tarefa. Os Web Services SOAP, que são uma evolução das RPC's (Remote Procedure Calls) e os Web Services REST, que trabalham de forma semelhante a qual nós, seres humanos utilizamos a World Wide Web. Roy Fielding, o criador do REST apresenta a arquitetura REST como uma alternativa ao estilo RPC para a implementação de Serviços Web. Este artigo pretende demonstrar os conceitos básicos do REST discutindo as suas características técnicas e demonstrar a sua utilização por meio de um exemplo prático.

2. O que é REST

Roy Fielding, o principal co-autor da especificação HTTP, em sua tese de doutorado, criou o termo REST (Representational State Transfer) que conforme sua definição, é um estilo arquitetural para sistemas distribuídos multimídia (Fielding, 2000).

REST propõe um conjunto de restrições às arquiteturas Web. A adoção destas restrições resultam em benefícios desejáveis. Fielding reúne uma série de estilos arquiteturais pré-existentes utilizados em aplicações Web a novas propostas para fundamentar este novo estilo arquitetural (Fielding, 2000).

3. Estilos Arquiteturais herdados pelo REST

Nesta seção são descritos os estilos arquiteturais herdados pela arquitetura REST.

3.1. Arquitetura Cliente-Servidor

REST utiliza a arquitetura Cliente-Servidor. Isto garante a separação de interesses e como benefícios podemos citar, a independência das aplicações clientes e servidoras, a portabilidade do cliente para múltiplas plataformas e a escalabilidade da aplicação servidora

Page 2: Aplicando Web Services Rest Com a API Jax Rs

(Fielding, 2000).

3.2. Falta de Estado (Stateless)

Todos os dados necessários ao processamento de uma requisição, deverão ser informados através da URI. Desta forma, o servidor não necessitará manter as informações das requisições anteriores e caberá a aplicação cliente manter o seu próprio estado de sessão (Richardson; Ruby, 2007).

Como benefícios da falta de estado, podemos citar: • Melhoria da confiabilidade: Se um cliente fizer uma requisição e algum eventual erro

ocorrer, ele necessitará apenas reenviar a requisição (Richardson; Ruby, 2007).• Escalabilidade de uma aplicação: Uma vez que uma requisição independe de outras,

vários servidores podem servir a mesma aplicação através de balanceamento de carga1 sem a necessidade de se coordenarem (Richardson; Ruby, 2007).

Entretanto, como desvantagem podemos citar a perca de performance de rede devido ao envio repetitivo dos mesmos dados a cada requisição (Fielding, 2000).

3.3. Cache

Permite que dados possam ser reutilizados, com a finalidade de economizar a utilização dos recursos de rede. Clientes e componentes intermediários podem armazenar cópias de mídias marcadas com o cabeçalho cacheable2 e estas cópias podem substituir requisições a aplicação servidora (Fielding, 2000).

4. Princípios do REST

Adicionalmente aos estilos arquiteturais pré-existentes adotados, Fielding criou novos princípios, recomendados à aplicações Web.

4.1. Recursos

Segundo a especificação do protocolo HTTP (versão 1.1), “Um recurso é um objeto ou serviço que pode ser identificado através de uma URI.” (Fielding et al, 1999).

4.2. Identificação dos Recursos através de URI

“Se uma parte das informações não tiver uma URI, não será um recurso, e realmente, não estará na web” (Richardson; Ruby, 2007). A URI tem a atribuição de identificar e localizar um recurso globalmente. Desta forma, ao ser identificado por uma URI, um recurso pode ser acessado remotamente em qualquer local do mundo.

4.3. Manipulação dos Recursos através de representações

“Os recursos são dissociados de suas representações para que seu conteúdo

1 Balanceamento de Carga: Diversas máquinas ligadas em rede e que em conjunto servem uma aplicação dividindo a carga de processamento requisitada.

2 Cacheable: Cabeçalho HTTP que informa se um dado pode possuir cópias temporárias remotas que podem substituir o dado original.

Page 3: Aplicando Web Services Rest Com a API Jax Rs

possa ser acessado em uma variedade de formatos (tais como HTML, XML, texto puro, PDF, JPEG e outros).” (Pautasso et al, 2008). Um recurso não é um dado, mas sim a informação que um dado representa. Uma informação pode ser disponibilizada em diversos formatos de dados diferentes. Por exemplo, uma cidade pode ser representada na forma de uma imagem de satélite, ou em na forma de um arquivo XML que armazena suas principais características geográficas.

Figura 01. Demonstração das representações de um recurso cidade.

Um recurso é manipulado através de suas representações, pois não há como manipular uma idéia, um conceito. Para criar um novo recurso, o cliente envia uma representação deste à aplicação servidora. É necessário que esta representação seja de um tipo suportado pelo servidor. Da mesma forma, para alterar um recurso, o cliente recupera uma representação, a altera e em seguida a envia novamente ao servidor.

4.4. Interface Uniforme

“Ao aplicar o princípio da engenharia de software de generalidade para a interface de componentes, a arquitetura geral do sistema é simplificado e da visibilidade das interações é melhorada.” (Fielding, 2000). Os recursos são dissociados das ações que os manipulam, desta forma, todos os recursos são manipulados através das mesmas ações. Estas ações são um pequeno e bem definido conjunto de métodos.

Ao disponibilizar seus serviços através de uma interface uniforme, a aplicação ganha em:

• Acessibilidade: Uma vez que possua a URI de um recurso, um cliente saberá manipulá-lo (Richardson; Ruby, 2007). Comparativamente, caso este mesmo serviço seja disponibilizado através de uma RPC, sua interface seria específica e isto faria com que o cliente necessitasse aprender como utilizá-la (como cada serviço recebe e envia dados).

• Economia de recursos de rede: Suas mensagens não necessitam conter meta-dados que informem dados sobre a interface utilizada (Richardson; Ruby, 2007).

• Performance: Possibilita a manipulação das mensagens de requisição e resposta pelos componentes intermediários, característica que faz com que serviços REST melhor se adequem à infra-estrutura de rede da internet. (Fielding, 2000)

Em sua tese, Fielding não restringe o REST ao protocolo HTTP, entretanto ele afirma ser este o único protocolo especificamente projetado para fornecer suporte a este estilo arquitetural. REST também não define quais são os métodos que esta interface deve possuir, mas ao adotar o HTTP, os métodos utilizados são aqueles definidos neste protocolo.

Page 4: Aplicando Web Services Rest Com a API Jax Rs

Figura 02. Demonstração comparativa entre uma interface específica e outra uniforme. (SILVA, 2008).

Alguns autores (como Pautasso et. al.) tentam mapear cada método HTTP para uma operação CRUD3, entretanto existem métodos HTTP que realizam mais de uma operação CRUD. A tabela abaixo demonstra a utilização destes métodos.

OperaçãoCRUD

MétodoHTTP

Definição

Consultar Get Recupera a representação de um Recurso.

Excluir Delete Remove um Recurso.

IncluirPut Cria um recurso, a URL é definida pelo cliente.

PostCria um recurso subordinado. A URL é definida pelo servidor e o

método é utilizado no recurso superior ao qual será criado.

AlterarPut Sobrescreve um recurso.

Post Altera o recurso, sem sobrescrever os dados já existentes do recurso.Tabela 01 (Richardson; Ruby, 2007)

Os métodos Get e Delete possuem uma única finalidade. O método Put pode criar um novo recurso, ou sobrescrever um já existente. O método Post possui diversas funções:

• Cria um novo recurso subordinado: Recursos que não podem ter a sua URI definida pelo cliente podem ser criados enviando sua representação em uma requisição POST a ao seu recurso pai. Nesta ocasião, o recurso pai é considerado um “recurso-fábrica”, pois é através deste que são criados novos recursos subordinados a este (Richardson; Ruby, 2007). Como exemplo desta situação, podem-se citar recursos que ao serem criados são persistidos em um banco de dados, e em sua URI seja informado o registro deste recurso.

• Altera um recurso alterando seu estado, sem sobrescrevê-lo e sem alterar os dados pré-existentes..

• Fornece um bloco de dados para um processo de tratamento de dados. Entenda bloco de dados como um formulário HTTP e processo de tratamento de dados como uma ação qualquer a ser executada no servidor (Richardson; Ruby, 2007). Esta forma de utilização do método Post é desaconselhada em uma arquitetura REST, uma vez que rompe os princípios de uma interface uniforme permitindo com que vários métodos

3 CRUD: Acrônimo de Create, Read, Update, Delete (Criar, Ler, Atualizar e Excluir)

Page 5: Aplicando Web Services Rest Com a API Jax Rs

específicos sejam criados para um recurso (Richardson; Ruby, 2007).

O protocolo HTTP também fornece dois métodos utilitários, o método Head que é utilizado quando se necessita obter apenas os meta-dados de um recurso (através de uma resposta com corpo vazio e com os mesmos cabeçalhos que seriam retornados a uma requisição do tipo Get) muito útil quando se necessita apenas obter os meta-dados de um recurso que possui uma representação extensa e o método Options que informa quais métodos HTTP um recurso está habilitado a responder (através de uma resposta sem conteúdo e com o cabeçalho Allow) (Richardson; Ruby, 2007).

4.5. Mensagens Auto-Descritivas

REST utiliza mensagens para trocar dados entre cliente e servidor, na prática estas mensagens são requisições e respostas HTTP. Estas mensagens fornecem meta-dados contendo informações relevantes aos clientes, servidores e componentes intermediários (Roteadores) (Fielding, 2000). Estes meta-dados são dissociados do conteúdo da mensagem, desta forma, dados necessários à transmissão desta mensagem ficam disponíveis aos componentes intermediários e podem ser utilizados por exemplo para controlar cache, detectar erros de transmissão, negociar a representação apropriada e executar autenticação e controle de acesso (Pautasso, 2008).

4.6. Estado da Aplicação e Estado do Recurso

Como visto na seção 1.1.2. REST são aplicações sem estado (stateless). Isto quer dizer que dados relativos às sessões dos clientes (Estados da aplicação) devem ser mantidos no cliente. Entretanto, os dados relativos aos recursos (Estados do Recurso), estes sim devem ser mantidos no servidor (Richardson; Ruby, 2007). Assim como um usuário pode salvar um link de um site, uma aplicação cliente pode armazenar o link de um recurso, e utilizá-lo posteriormente. Isto é possível devido ao estado do recurso que é mantido pelo servidor, desta forma possibilitando sua manipulação em um período posterior. Sendo assim, dados que necessitam ser mantidos por mais de um ciclo de uma requisição, devem se tornar recursos (Richardson; Ruby, 2007).

4.7. Hipermídia como o motor de estado da aplicação

O servidor não é responsável por manter o estado da aplicação, entretanto ele pode guiar o cliente fornecendo os próximos passos que este poderá seguir (Richardson; Ruby, 2007). Isto é feito através de links contidos nos recursos requisitados. Cabe então ao cliente escolher dentre os links fornecidos. Da mesma forma que acontece com um usuário que navega pelas páginas de um site, uma aplicação cliente navega por uma aplicação REST.

Como exemplo disto, podemos citar uma consulta de cidades que pode retornar um XML contendo uma lista de cidades, e para cada cidade, poderá ser informado apenas o seu nome e o seu link (tornando-se desnecessário enviar os dados de todas as cidades, o que resulta em economia dos recursos de rede). Em seguida, para editar os dados de uma determinada cidade, o cliente então utiliza o seu link, de forma a obter um novo XML contendo os dados desta cidade, em seguida, editando este XML e o reenviando ao servidor em uma requisição Put.

5. JAX-RS

Page 6: Aplicando Web Services Rest Com a API Jax Rs

Visando facilitar o desenvolvimento de serviços REST, a comunidade Java através de um Java Community Process (JCP) desenvolveu a especificação JSR-311 (Java Specification Request 311) também conhecida como JAX-RS (Java API for RESTful Web Services) (Hadley; Sandoz, 2008).

Esta especificação tem como objetivos:• Desenvolvimento baseado em POJOs: Classes java serão POJOs disponibilizados

como recursos através da utilização de anotações (Hadley; Sandoz, 2008).• Centrado no HTTP: Conceitualmente REST não se restringe a este protocolo, porém

este é o único protocolo existente para este estilo arquitetural (Hadley; Sandoz, 2008).• Independência de formato: Um recurso poderá ser disponibilizado através de diversas

representações sem codificação adicional (Hadley; Sandoz, 2008).• Independência de contêiner: Uma aplicação JAX-RS deverá ser portável a qualquer

contêiner JEE (Hadley; Sandoz, 2008).• Inclusão no Java EE 6 (Hadley; Sandoz, 2008).

5.1. Classes Recursos

“Utilizando JAX-RS um recurso web é implementado como uma classe recurso e as requisições processadas por métodos recursos.” (Hadley; Sandoz, 2008). Ou seja, com a JAX-RS é possível criar uma aplicação REST definindo classes que irão agir como recursos.

5.1.1. Definindo a URI de um Recurso

Em JAX-RS a URI de um recurso começa a ser construída com o contexto da aplicação. Opcionalmente, um diretório lógico (ou caminho) pode ser definido especificamente para agrupar todos os recursos JAX-RS. Em seguida vem o caminho do recurso raiz, depois os caminhos dos possíveis sub-recursos. Ao final da URI, poderão ser opcionalmente informados os parâmetros de matriz e os parâmetros de consulta.

contexto da aplicação + diretório dos recursos + recursos + parâmetroshttp://localhost:8080/fretesRest/servicos/recursoraiz/sub1/sub2?paramConsulta=true

Listagem 01.

A parte da URI que forma o contexto da aplicação é construída pelo host, porta e nome da aplicação, o diretório dos recursos, é informado no descritor de implantação web.xml. O restante da URI é construído nas classes e métodos recursos através da anotação @Path.

5.1.2. Classe Recurso raiz

Para que uma classe se torne um recurso-raiz basta a esta ser anotada com @Path e no argumento desta anotação ser definido um prefixo URI para este recurso conforme a listagem abaixo.

0102

@Path(“/recurso_raiz”)public class RecursoRaiz() { //... }

Listagem 02.

Page 7: Aplicando Web Services Rest Com a API Jax Rs

5.1.3. Ciclo de vida de uma Classe Recurso

“Por padrão, uma nova instância de uma classe recurso é criada para cada requisição.” (Hadley; Sandoz, 2008). Em outras palavras, para cada requisição será instanciada uma nova classe recurso e após o envio da resposta, esta instância então ficará disponível para ser destruída pelo Garbage Collector.

Porém, as implementações dessa especificação poderão definir novos ciclos de vida para as classes recurso. A implementação de Referência Jersey, disponibiliza dois novos escopos através das anotações @PerSession (uma classe recurso por sessão) e @Singleton.(uma classe recurso para toda a aplicação) (Sun Microsystems, 2009).

5.2. Métodos Recurso

“Métodos Recursos” são responsáveis por responder requisições enviadas a uma Classe Recurso. Para que um método se torne um Método Recurso, deve se informar quais métodos HTTP este método estará designado a responder (Hadley; Sandoz, 2008). JAX-RS define um conjunto de anotações que representam os métodos HTTP. São elas: @GET, @PUT, @DELETE, @POST, @HEADER e @OPTIONS. A listagem abaixo demonstra um Método Recurso que irá responder a requisições Put enviadas à sua classe recurso.

0102030405060708

@Path(“/recurso_raiz”)public class RecursoRaiz() {

@PUTpublic void metodoRecurso(){

//...}

}

Listagem 03. Exemplo de uma Classe Recurso que possui um Método Recurso.

Caso não exista um método explicitamente designado a receber requisições para os métodos Head e Options, JAX-RS irá lhes fornecer suporte automático. Para requisições do tipo Options, a implementação JAX-RS irá retornar uma resposta com base nas informações sobre os recursos disponíveis e para as requisições do tipo Header, caso haja um método designado a receber requisições do tipo Get, este também irá responder suas requisições. Porém, se um método Get possuir uma lógica complexa para construir o corpo da resposta, designar um método exclusivamente para atender as requisições do tipo Head irá fornecer uma melhoria no desempenho para as requisições deste tipo, uma vez que este método será projetado para retornar apenas os meta-dados do seu Recurso.

5.2.1. Parâmetros

Os parâmetros de um método recurso podem ser utilizados para receber dados do cliente, estes dados podem ser extraídos da requisição através da URI, dos cabeçalhos de requisição ou de cookies. Segue abaixo, a lista das anotações utilizadas em parâmetros de forma a definir que estes irão receber estes dados.

Anotação Descrição

@PathParam Extrai o valor de um parâmetro localizado no padrão da URI.

@MatrixParam Extrai o valor de um parâmetro de matriz da URI.

Page 8: Aplicando Web Services Rest Com a API Jax Rs

@QueryParam Extrai o valor de um parâmetro de consulta da URI.

@HeaderParam Extrai o valor de um cabeçalho HTTP.

@CookieParam Extrai o valor de um cookie.Tabela 02 (Hadley; Sandoz, 2008)

Um Método Recurso poderá possuir apenas um parâmetro que não utilize nenhuma das anotações citadas na tabela acima, pois este parâmetro não anotado será o responsável por receber o conteúdo da requisição. A tabela abaixo demonstra um Método Recurso que possui dois parâmetros, um receberá uma variável de consulta e o outro o conteúdo da requisição.

0102030405060708

@Path(“/recurso_raiz”)public class RecursoRaiz() {

@PUTpublic String metodoRecurso(@QueryParam(“param”) String param,

String conteudo){//...

}}

Listagem 04. Exemplo de um Método Recurso que receberá um parâmetro de consulta eum conteúdo.

5.2.2. Retornos

JAX-RS fornece um mapeamento entre os tipos Java que um método recurso pode retornar e os tipos de conteúdo da resposta HTTP. Este mapeamento é realizado pela implementação JAX-RS que utiliza classes denominadas Provedores de Entidade. Estas classes serão descritas na seção 5.7.

Os tipos retornados poderão ser void, Response ou qualquer outra classe Java. Basicamente, para um método que retorne void ou null, será gerada uma resposta com corpo vazio (e mensagem de status número 204 – no content). Um método que retorne um objeto java por padrão irá retornar uma resposta com o conteúdo deste objeto, e mensagem de status número 200 (status ok) (Hadley; Sandoz, 2008).

Caso o desenvolvedor necessite retornar uma resposta personalizada, como por exemplo, informar uma mensagem de status diferente, adicionar novos cabeçalhos ou cookies, este poderá retornar um objeto do tipo Response (Silva; Buback, 2008).

5.3. Sub-Recursos

“Sub-Recursos” são representados por Métodos Recurso. Um Método Recurso poderá implementar o Sub-Recurso, ou poderá alocar uma outra Classe Recurso correspondente a este Sub-Recurso (Hadley; Sandoz, 2008). Em ambos os casos, o método em questão deverá ser anotado com @Path para se definir o prefixo URI que identifica o Sub-Recurso.

O método que implementa o Sub-Recurso é denominado Método Sub-Recurso (listagem 00). Já o método que localiza um recurso correspondente é denominado Alocador de Sub-Recurso (listagem 00). Mais precisamente, o alocador de sub-recurso deverá retornar a instância de uma classe recurso.

Page 9: Aplicando Web Services Rest Com a API Jax Rs

0102030405060708

@Path(“/recurso_raiz”)public class RecursoRaiz() {

@GET@Path(“/metodo_sub_recurso”)public void metodoSubRecurso(){

//...}

}

Listagem 05. Exemplo de um Método Sub-Recurso

0102030405060708

@Path(“/recurso_raiz”)public class RecursoRaiz() {

@GET@Path(“/metodo_alocador_sub_recurso”)public RecursoAlocado metodoAlocadorSubRecurso(){

return new RecursoAlocado();}

}

Listagem 06. Exemplo de um Método Alocador de Sub-Recurso

5.4. Padrões de URI

Em um padrão de URI, podemos definir parâmetros, estes parâmetros consistem em um nome contido em um par de chaves. Adicionalmente, podemos definir uma expressão regular que deverá ser atendida, para que a requisição seja válida. Por exemplo, se um parâmetro for definido para receber um valor numérico, podemos definir uma expressão regular que aceite apenas dígitos numéricos para este parâmetro. Caso a URI da requisição não atenda a esta regra a requisição será inválida.

01020304

@Path(“/cidade/{id} : [0-9]+”)public String testeRegex(@PathParam(“cidade”) String idade){

return “Idade = ” + idade;}

Listagem 07. Exemplo da definição de um padrão de URI.

5.5. Tipos de mídias

Um dos objetivos da JAX-RS define que um recurso poderá ser disponibilizado em diversos formatos de mídia sem que para isto, o desenvolvedor tenha que escrever código extra para fornecer esta flexibilidade. Caberá ao desenvolvedor apenas designar ao recurso quais formatos este poderá produzir ou consumir. Esta designação é realizada através das anotações @Produces e @Consumes onde em seus parâmetros deverá ser passada a lista de tipos de mídia (conhecidos pela especificação do protocolo HTTP como códigos media-type) que identificam os formatos desejados.

Por padrão, um recurso que não possua a informação de quais tipos de mídia pode consumir ou produzir, receberá o tipo genérico “*/*”, dessa forma, aceitando qualquer tipo de mídia. A informação sobre quais mídias uma requisição pode enviar, ou espera receber é fornecida pelos seus cabeçalhos “Accept header” e “Content-Type” respectivamente. Ao especificar quais tipos de mídia um recurso poderá consumir ou produzir, qualquer requisição que não atender a esta regra, não irá ser processada por este recurso.

5.6. Provedores

Page 10: Aplicando Web Services Rest Com a API Jax Rs

A seção anterior demonstrou como são definidas as representações de tipos de formato que um recurso poderá consumir e produzir e que caberá a implementação JAX-RS fazer a conversão entre os objetos Java e os corpos das requisições.

A tarefa de realizar esta conversão é atribuída à classes denominadas provedores de entidade. JAX-RS define que suas implementações forneçam provedores de entidade para os tipos Java abaixo:

Tipos de Mídia Tipos Java

Todos os tipos de mídia (*/*) byte[]

Todos os tipos de mídia de texto (text/*) java.lang.String

Todos os tipos de mídia (*/*) java.io.InputStream

Todos os tipos de mídia (*/*) java.io.Reader

Todos os tipos de mídia (*/*) java.io.File

Todos os tipos de mídia (*/*) javax.activation.DataSource

Todos os tipos de mídia (*/*) StreamingOutput

Todos os tipos de mídia (*/*) javax.xml.transform.Source

Tipos XML (text/xml, application/xml e application/*+xml)

javax.xml.bind.JAXBElement e classes JAXB de aplicação.

Conteúdo de formulário (application/x-www-form-urlencoded)

MultivaluedMap<String, String>

Tabela 03 Mapeamento entre Tipos Java e Tipos de mídia (Hadley; Sandoz, 2008).

Desta forma, caso seja necessário utilizar um tipo java diferente dos citados acima, deverá ser construído um novo provedor de entidade para este tipo.

Todo provedor de entidade deve ser decorado com a anotação @Provider e implementar ao menos uma destas duas interfaces: MessageBodyReader (que realiza a conversão do corpo da requisição para o tipo Java) e MessageBodyWriter (que realiza a conversão do tipo Java para o corpo da resposta).

0102030405

@Providerpublic class ProvedorTeste implements

MessageBodyHeader<ClasseASerConvertida>{// ... código de conversão

}

Listagem 08. Demonstração de um Provedor.de conteúdo.

5.7. Contextos

É possível obter informações do contexto da aplicação e das requisições individuais. A especificação JAX-RS fornece um conjunto de classes responsáveis por representar estas informações. Estas classes são denominadas classes contexto.

Instâncias destas classes são fornecidas pela implementação JAX-RS através da anotação @Context, que pode ser utilizada em recursos(em atributos da classe e em

Page 11: Aplicando Web Services Rest Com a API Jax Rs

parâmetros dos métodos) e em provedores de entidade, conforme o exemplo abaixo.

010203

public String teste(@Context UriInfo uriInfo){// ...

}

Listagem 08. Exemplo da utilização de uma classe contexto.

Segue abaixo a lista de classes de contexto:

Classe Descrição

UriInfo Obtém informações da URI, como parâmetros de consulta e URI absoluta.

HttpHeaders Obtém informações dos cabeçalhos e cookies.

Request Obtém informações sobre a requisição

SecurityContext Obtém informações de segurança fornecida através de JAAS (Java Authorization and Authentication Security) como o tipo de autenticação e usuário principal.

Providers Obtém um provedor de conteúdo da aplicação.Tabela 04. Lista de Classes Contexto

5.8. Exceções

Por padrão, ao ocorrer uma exceção em um Método Recurso uma resposta com código de status 500 (Erro interno no servidor) é enviada ao cliente. Entretanto, caso o desenvolvedor necessite retornar uma exceção com status diferente este pode faze-lo lançando uma exceção javax.ws.rs.WebApplicationException definida na API JAX-RS. A listagem abaixo demonstra a utilização desta exceção:

010203040506

try{ // ...catch(Exception e){ throw new WebApplicationException(e, 404);// informando status da resposta}

Listagem 09

Page 12: Aplicando Web Services Rest Com a API Jax Rs

6. Desenvolvendo um Web Service REST - Provedor de serviço REST

Nesta seção, será desenvolvida uma aplicação que irá disponibilizar alguns serviços para uma empresa de Fretes. Este exemplo visa demonstrar o uso prático dos conceitos descritos neste artigo. Inicialmente serão apresentados os requisitos, logo em seguida será demonstrada uma forma de se projetar os seus recursos. Esta aplicação será implementada utilizando a linguagem Java e a API JAX-RS.

6.1 Requisitos

Uma empresa especializada em realizar fretes entre empresas deseja disponibilizar serviços para que softwares de seus clientes possam obter os preços, os tempos estimados e agendar fretes. Segue abaixo, a lista dos requisitos previstos para esta aplicação:

Nº Serviços Descrição

01 Consultar Empresa. Permite a uma empresa obter a referência a outra.

02Buscar preço e tempo estimado de um frete.

Informando a empresa destino, o peso da mercadoria e a data de envio, a empresa origem poderá obter o preço e o tempo estimado deste frete.

03 Agendar um fretePermite a empresa origem agendar um frete, será necessário informar a empresa destino, a data de envio e o peso da mercadoria.

04 Editar um frete Permite que um frete seja alterado ou excluído.

05 Cancelar um frete Permite que um frete seja excluído.Tabela 05 – Serviços Previstos para a aplicação.

6.2. Projeto de recursos

Em sua obra Web Services RESTful (2007), os autores Leonard Richardson e Sam Ruby sugerem um procedimento para o projeto de Recursos constituído por uma sequência de etapas, este procedimento será descrito logo abaixo.

1. Descobrir o conjunto de dados2. Dividir o conjunto de dados em recursos

Para cada tipo de recurso:

3. Nomear os recursos com URI's4. Exibir um subconjunto da interface Uniforme5. Construir a(s) representações aceitas do cliente6. Construir a(s) representações fornecidas pelo cliente7. Integrar este recurso aos recursos existentes, usando links e formulários de hipermídia8. Considerar o curso típico dos eventos: o que deve acontecer?9. Considerar as condições de erro: o que pode dar errado?

As seções posteriores visam demonstrar a aplicação deste procedimento.

Page 13: Aplicando Web Services Rest Com a API Jax Rs

6.2.1 Descobrir o conjunto de dados

Nesta etapa, busca-se realizar um levantamento dos tipos de dados que serão exibidos e manipulados pelos clientes (Richardson; Ruby, 2007). A aplicação de exemplo visa disponibilizar informações sobre empresas e fretes.

6.2.2 Dividir o conjunto de dados em recursos

“Um serviço web REST exibe seus dados e seus algoritmos através de recursos.” (Richardson; Ruby, 2007). Para organizar os conjuntos de dados e as funcionalidades na forma de recursos, Richardson e Ruby (2007) proporam uma forma de se classificar os recursos:

• Recursos que representam dados: As instâncias dos tipos de dados definidos na seção anterior são consideradas recursos deste tipo.

• Recursos que representam funcionalidades: Quando um recurso necessita expor uma funcionalidade que não se enquadra na interface uniforme, esta funcionalidade é convertida em um sub-recurso.

• Recursos predefinidos: São recursos de alto nível hierárquico e permanentes que servem para agrupar sub-recursos.

Para a aplicação de exemplo, para cada tipo de dado definido na seção anterior, será criado um recurso pré-definido que será responsável por agrupar todas as instâncias deste tipo e todas as funcionalidades aplicadas a este tipo de dado que não se enquadram na interface uniforme. A tabela abaixo apresenta os recursos definidos:

Recursos Pré-definidos

Empresas Recurso único que agrupará recursos do tipo empresa.

FretesRecurso único que agrupará recursos do tipo frete e funcionalidades não vinculadas a um frete existente.

Recursos que representam dados

Empresa Existirá um recurso deste para cada instância de empresa.

Frete Existirá um recurso deste para cada instância de frete.

Recursos que representam funcionalidades

CotaçãoRecurso que representa a funcionalidade de calcular o preço e o tempo estimado (em dias corridos) de um frete.

Tabela 06 – Recursos definidos.

6.2.3. Nomear os recursos com URI's

Definidos os recursos, deve-se então criar o padrão de suas URI´s. Uma boa estratégia para a construção das URI's é começar definindo os Recursos-Raízes. Para a aplicação de exemplo, os recursos pré-definidos (Fretes e Empresas) serão definidos como Recursos-Raízes. Quanto aos recursos que representam dados (recursos dos tipos frete e empresa) e aos recursos que representam funcionalidades (Cotação) serão subordinados aos recurso pré-definidos citados acima.

Page 14: Aplicando Web Services Rest Com a API Jax Rs

Será adotado que não existirá letras maiúsculas nas URI's desta aplicação. E que os recursos que representam dados serão identificados pelo padrão: /<Tipo>s/{id}, onde id será uma variável de Path que informará o número identificador desta instância. A tabela abaixo demonstra o padrão das URI's definido para a aplicação de exemplo:

Nº Padrão da URI Objetivos

1 ➢ /empresas • Lista recursos do tipo empresa.

1.1 /{id} • Representa um recurso do tipo empresa já cadastrado.

2 ➢ /fretes• Lista recursos do tipo frete.• Recurso-fábrica4 para recursos do tipo frete.

2.1 /{id} • Representa um recurso do tipo frete já cadastrado.

2.2 /cotacao • Informa o preço e o tempo estimado de um frete.Tabela 07 – Definição dos padrões de URI's.

6.2.4. Exibir um subconjunto da interface Uniforme

Nesta etapa, são definidos quais métodos HTTP cada recurso estará habilitado a responder (Richardson; Ruby, 2007). As empresas serão apenas consultadas e os fretes poderão ser incluídos, alterados, excluídos e consultados. O Recurso que representam funcionalidades (“cotacao”) será consultado.

Aplicando as considerações da seção 4.4 à aplicação de exemplo, pode-se definir que todos os recursos que necessitem ser consultados responderão ao método Get e os recursos que puderem ser excluídos terão seu método Delete habilitado. Já as operações de inclusão e alteração necessitam ser especificados para cada recurso. Como somente os Recursos do tipo frete deverão possuir estas ações, para incluir será utilizado o método Post no recurso pré-definido fretes, pois será a aplicação servidora a responsável por criar a URI de cada novo recurso deste tipo. Para alterar será utilizado o método Put pois há a necessidade de se alterar os dados já informados nestes recursos. A tabela abaixo demonstra quais métodos serão disponibilizados para cada recurso e adicionalmente informa quais os parâmetros de consulta poderão ser utilizados:

Nº Padrão da URI MétodosOperação

CRUDParâmetros de consulta

1 ➢ /empresas Get Consultar nome, cidade

1.1 /{id} Get Consultar -

2 ➢ /fretesGet Consultar

origem, destino, dataenvio, peso,dataenvioinicio, dataenviofim

Post Incluir (um Frete) -

2.1 /{id} Get Consultar -

Delete Excluir -

4 Recurso-Fábrica: Um recurso que tem o seu método Post utilizado para criar novos recursos subordinados. Mais detalhes na seção 4.4.

Page 15: Aplicando Web Services Rest Com a API Jax Rs

Put Alterar -

2.2 /cotacao Get Consultar origem, destino, dataenvio, pesoTabela 08 – Definição dos padrões de URI's.

6.2.5. Construir as representações aceitas do cliente

O objetivo desta etapa é definir os dados a serem informados no corpo das respostas enviadas ao cliente e em quais formatos estes dados poderão estar (Richardson; Ruby, 2007). Para a aplicação de exemplo, as representações serão disponibilizadas nos formatos: XML e JSON.

JAX-RS faz uso da API JAXB para realizar o processo de conversão entre objetos Java e arquivos XML (Sun Microsystems Inc., 2009), bastando ao desenvolvedor final apenas realizar o mapeamento entre estes dois artefatos através de anotações fornecidas por esta API. Estas anotações são utilizadas na classe Java a ser convertida. Estas classes mapeadas, podem ser utilizadas nos Métodos-Recursos, em seus parâmetros ou em seus tipos de retorno. Entretanto, classes provedoras podem ser escritas para utilizar as anotações JAXB para fornecer representações em outros formatos, a implementação Jersey possui provedores5 para arquivos JSON. Para a aplicação de exemplo, serão criadas as classes listadas na tabela abaixo:

Classe Java Estrutura do XML@XmlRootElement(name="empresa")public class Empresa {

private Integer id; private URI uri; private String nome;

@XmlAtribute public Integer getId(){//...} @XmlAtribute public URI getUri(){//...}

// Gets e Sets omitidos}

<empresa id="1" uri="http://fretes.com/empresas/01"> <nome>1</nome></empresa>

@XmlRootElement(name="frete")public class Frete{

private Long id; private URI uri; private Double peso; private Date data; private Empresa origem; private Empresa destino;

@XmlAtribute public Integer getId(){//...} @XmlAtribute public URI getUri(){//...}

// Gets e Sets omitidos}

<frete id="1" uri="http://frete.com/fretes/01"> <data>2009/10/01</data> <destino id="2" uri="http://frete.com/empresas/02"> <nome>Empresa 2</nome> </destino> <origem id="1" uri="http://frete.com/empresas/01"> <nome>Empresa 1</nome> </origem> <peso>1</peso></frete>

@XmlRootElement(name="cotacao")public class Cotacao{

<cotacao>

5 Classes Provedoras são descritas na seção 5.6.

Page 16: Aplicando Web Services Rest Com a API Jax Rs

private Double preco; private Date dataenvio; private Integer tempoestimado;

// Gets e Sets omitidos}

<dataenvio>2009/10/28</dataenvio> <preco>176.00</preco> <tempoestimado>3</tempoestimado></cotacao>

Tabela 09 – Beans mapeados com as anotações da API JAXB, permitindo com que instâncias dessas classes possam ser convertidas em arquivos XML.

A anotação @Produces (ver seção 5.5 – Tipos de mídia) será utilizada nas Classes Recurso para informar os formatos de arquivos que poderão ser retornados nas mensagens de respostas. A listagem abaixo demostra a sua utilização:

0102

@Produces({"application/xml", "application/json"})public class FretesRecurso{ // ... }

Listagem 10

6.2.6. Construir as representações fornecidas pelo cliente

Esta etapa é semelhante a anterior, porém nesta são definidas as representações que poderão ser fornecidas pelo cliente, em outras palavras, os dados existentes nos conteúdos das requisições dos clientes e em quais formatos poderão ser escritos (Richardson; Ruby, 2007). Para todos os recursos da aplicação de exemplo, as representações fornecidas pelos clientes poderão ser dos tipos: XML e JSON. Apenas os recursos do tipo frete serão fornecidos pelo cliente no momento da inclusão e da alteração.

Conforme demonstrado na seção 5.5 (tipos de mídias), ao utilizar a API JAX-RS, as Casses-Recurso e Métodos-Recurso utilizam a anotação @Consumes para informar os formatos de arquivos aceitos conforme demonstrado na listagem abaixo:

0102

@Consumes({"application/xml", "application/json"})public class FretesRecurso{ // ... }

Listagem 11

6.2.7. Integrar este recurso aos recursos existentes, usando links e formulários de hipermídia

As representações dos recursos podem apresentar links para os recursos com os quais se relaciona. Isto permite com que a aplicação cliente possa “navegar” pelos recursos como acontece com a “web humana” (Richardson; Ruby, 2007). Em nossa aplicação, a representação de um frete no formato XML irá conter links para as empresas de origem e destino (conforme demonstrado nos arquivos XML de exemplo demonstrados na tabela 09).

6.2.8. Considerar o curso típico dos eventos: o que deve acontecer?

Nesta etapa define-se os processamentos que deverão ocorrer para as requisições. Para a aplicação de exemplo, espera-se que o estado dos recursos dos tipos fretes e empresas sejam persistidos em um banco de dados. Para acessar o banco de dados será utilizado o padrão de projeto DAO (Data Acess Object – Objeto de acesso aos dados). O diagrama de sequência abaixo demonstra a interação realizada ao consultar recursos do tipo empresa.

Page 17: Aplicando Web Services Rest Com a API Jax Rs

Figura 03. Diagrama de sequência demonstrando a iteração realizada ao recuperar a representação em XML do recurso Empresas.

6.2.9. Considerar as condições de erro: o que pode dar errado?

Nesta última etapa, o desenvolvedor necessita implementar o tratamento para os possíveis erros que poderão ocorrer, como por exemplo uma requisição inválida (Richardson; Ruby, 2007). Para a aplicação de exemplo, podemos restringir que as variáveis de caminho id dos recursos dos tipos Frete e Empresa sejam formados apenas por caracteres numéricos. Utilizando a API JAX-RS esta validação pode ser realizada adicionando um padrão de expressão regular que estas variáveis deverão possuir conforme demonstrado na seção 5.4. Ao receber uma requisição que não atenda a este padrão, uma resposta com mensagem de status de número 404 (não encontrado). Caso ocorra uma exceção no momento do processamento da requisição a implementação da JAX-RS utilizada deverá retornar uma mensagem de status 500 (Erro interno no servidor) conforme citado na seção 5.8.

6.3. Implementando a aplicação fornecedora

Após o levantamento das características dos recursos a serem projetados, é chegada a hora de implementá-los. A tabela abaixo demonstra a implementação do recurso pré-definido Fretes.

01020304050607080910111213141516171819

@Path("/fretes") // Padrão de URI da Classe Recurso Raiz@Consumes({"application/xml", "application/json"}) // formatos aceitos@Produces({"application/xml", "application/json"}) // formatos enviados@Singleton // Definindo ciclo de vida da Classe Recursopublic class FretesRecurso {

@Context // Classe de contexto Jersey que recupera outras Classes Recurso protected ResourceContext resourceContext;

@GET public List<Frete> consultarTodos( // Parametros de consulta (seção 1.1) @QueryParam("origem") Integer origem, @QueryParam("destino") Integer destino, @QueryParam("peso") Double peso, @QueryParam("data") Date data, @QueryParam("data") Date dataEnvioInicio, @QueryParam("data") Date dataEnvioFim) { return FreteDAO.consultar(

Page 18: Aplicando Web Services Rest Com a API Jax Rs

202122232425262728293031323334353637383940414243444546474849

origem, destino, peso, data, dataEnvioInicio, dataEnvioFim); }

@POST public Response incluirFrete(Frete frete) { try{ FreteDAO.incluir(frete); resourceContext.getResource(FreteRecurso.class).alterar(frete); return Response.created(frete.getUri()).build(); } catch (Exception e){ throw new WebApplicationException(e); } }

@Path("/{id : [0-9]+}") // Utilização de Expressão regular public FreteRecurso getFreteRecurso() { // Método alocador de sub-recurso return resourceContext.getResource(FreteRecurso.class); }

@GET @Path("/cotacao") public Cotacao getCotacao( // Método sub-recurso (seção 1.1) @QueryParam("origem") Integer origem, @QueryParam("destino") Integer destino, @QueryParam("peso") Double peso, @QueryParam("data") Date data) {

return FreteDAO.cotacao(origem, destino, peso, data); }}

Listagem 11 – Recurso Raíz FreteRecurso.

A tabela abaixo apresenta algumas observações sobre a implementação da classe FretesRecursos e indica em qual seção deste artigo encontram-se mais detalhes:

Linha Seção Descrição

01 5.1.2 Caminho da Classe Recurso Raiz.

02 5.5 Lista de formatos que poderão ser enviados nas requisições.

03 5.5 Lista de formatos que poderão ser enviados nas respostas.

04 5.1.3 Definição do ciclo de vida.

07 5.7Atributo utilizado para receber classe de contexto ResourceContext. Esta classe de contexto é uma classe exclusiva da implementação Jersey e é utilizada para recuperar instâncias de outras Classes Recursos.

10 5.2Exemplo de um Método Recurso, designado a responder a requisições de um método HTTP especificado.

13 5.2.1.Exemplo de parâmetros do Método Recurso que receberão os valores dos parâmetros de consulta das requisições HTTP.

34 5.4. Definindo padrão de expressão regular para uma variável de caminho.

35 5.3.Exemplo de um Método alocador de Sub-Recurso. O Método Recurso getFreteRecurso contido na Classe Recurso FretesRecurso está alocando requisições com o padrão /fretes/{id} para a Classe Recurso FreteRecurso.

41 5.3.Exemplo de um Método Sub-Recurso. O Método Recurso getCotacao() representa um Sub-Recurso pois sua URI

Page 19: Aplicando Web Services Rest Com a API Jax Rs

Tabela 10 – Comentários sobre o código da Classe Recurso FretesRecurso (listagem 11).

A listagem abaixo demostra o código da Classe Recurso Frete, que representa os recursos que representam dados do tipo Frete:

01020304050607080910111213141516171819202122

@Singleton // Haverá apenas uma instância desta classe para a aplicaçãopublic class FreteRecurso {

@Context private UriInfo uri;

@GET public Frete consultar(@PathParam("id") Integer id) { return FreteDAO.consultarPorId(id); }

@PUT public Frete alterar(@PathParam("id") Integer id, Frete frete) { frete.setUri(uri.getAbsolutePath()); return FreteDAO.alterar(id, frete); }

@DELETE public void excluir(@PathParam("id") Integer id) { FreteDAO.excluir(id); }}

Listagem 12 – Sub-Recurso FreteRecurso, representa todos os recursos do tipo frete.

Conclusão

O objetivo deste artigo foi apresentar a tecnologia REST como uma ferramenta utilizada para promover a computação distribuída através da publicação de Serviços disponibilizados na Web. Criada pelo principal autor do protocolo HTTP, este estilo arquitetural é formado por um conjunto de regras que quando seguidas pelas aplicações distribuídas, fazem com que estas utilizem de forma mais apropriada a infra-estrutura da Web, melhorando os aspectos de acessibilidade, economia de recursos de rede, melhoria de performance e escalabilidade, conforme descrito na seção 3.

Entretanto, para implementar uma aplicação no estilo REST, é necessário manipular mensagens HTTP, desta forma, desenvolvedores não habituados a utilizar este protocolo, podem encontrar dificuldades ao tentarem construir serviços REST. Da mesma forma, estes desenvolvedores podem criar serviços que não se adéqüem às restrições definidas pelo REST, o que resultaria em serviços que não se beneficiariam das vantagens oferecidas por este estilo arquitetural.

Com o desenvolvimento da aplicação de exemplo, pode-se constatar que:• Ao utilizar a API JAX-RS, o desenvolvimento de serviços REST torna-se uma

atividade simples e produtiva: Tarefas como a conversão de dados realizada entre os objetos Java e as representações enviadas ao cliente são automatizadas.

• Serviços REST são disponibilizados através de Recursos. que devem ser corretamente projetados: Deve-se definir a hierarquia dos Recursos, quais métodos cada recurso irá responder, quais representações serão aceitas e fornecidas.

• Ao utilizar JAX-RS sem o conhecimento das características que um serviço REST deve possuir, pode ocasionar em recursos mal projetados, por exemplo, um Método-

Page 20: Aplicando Web Services Rest Com a API Jax Rs

Recurso que responda a requisições do tipo GET não pode excluir recursos.

Bibliografia

FIELDING, Roy T. Architectural Styles and the Design of Network-based Software Architectures. 2000. Tese (Doutorado) - UNIVERSITY OF CALIFORNIA, IRVINE 2000. Disponível em: <http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm>. Acesso em 12 setembro 2009.

RICHARDSON, Leonard; RUBY, Sam. RESTful Serviços Web. 1. ed. Rio de Janeiro: Alta Books, 2007. 336 p.

Fielding, et al. Hypertext Transfer Protocol – HTTP/1.1. Junho 1999. Disponível em: <http://www.ietf.org/rfc/rfc2616.txt>. Acesso em 15 setembro 2009.

HADLEY, Marc ; SANDOZ Paul.JAX-RS: Java API for RESTful Web Services. Sun Microsystems, Inc., Santa Clara CA USA, setembro 2008. Disponível em: <https://jsr311.dev.java.net/drafts/spec2 0090917.pdf >. Acesso em 20 setembro 2009.

SUN MICROSYSTEM INC.. The Java EE Tutorial.Santa Clara CA USA, 2009. Disponível em: <http://dlc.sun.com/pdf/820-7627/820-7627.pdf>. Acesso em 7 setembro 2009.

SILVA, Bruno L. P.; BUBACK, Silvano N. JSR 311 e Jersey: Web services no Java EE. Java Magazine, Grajaú RJ, v. 6 n. 60, p.72-82, ago.2008.

PAUTASSO, Cesare; ZIMMERMANN, Olaf; LEYMANN, Frank. RESTful Web Services vs. “Big” Web Services: Making the Right Architectural Decision. 17th International World Wide Web Conference (WWW2008), Beijing China, p.805-814, abr. 2008. Disponível em: <http://www2008.org/papers/pdf/p805-pautassoA.pdf> Acesso em: 7 Set. 2009.