Neste artigo vamos abordar uma nova arquitetura para construção de serviços. Estamos falando de serviços Restful baseados nos princípios arquiteturais definidos por REST. Utilizaremos os frameworks Apache CXF e Apache Camel para demonstrar como é simples implementar serviços que seguem o padrão Restful construídos com a especificação JAX-RS.

Operações HTTP para serviços Restful
Figura 1. Operações HTTP para serviços Restful

De forma bem simples, REST (Representation State Transfer) é um conjunto de princípios. A promessa é que uma vez seguidos esse conjunto de princípios enquanto você desenha a sua aplicação, ao final você terá um sistema que explora e faz uso de todo o benefício da arquitetura Web. Vamos ver rapidamente quais são os princípios:

  • Endereçamento. é a ideia que todo objeto ou recurso no seu sistema é passível de ser encontrado através de um identificador único. Na web qualquer recurso está associado a um endereço URI (Uniform Resource Identifier). Uma URL é apenas um tipo de URI. Uma URI tem a seguinte forma: scheme://host:port/path?queryString#fragment. Veja o seguinte exemplo: http://example.com/customers?cpf=1234321. Ela não poderia representar facilmente um cliente? O retorno à chamada dessa URI poderia ser um documento com uma série de “links” para outras informações do mesmo cliente ou outras entidades ou pessoas relacionadas a esse cliente.
  • Interface Uniforme. se existem recursos com endereços, que tal acessá-los através de um conjunto bem definido de operações ou ações? Em HTTP são chamados de verbos (GET, POST, PUT, DELETE etc.).
  • Orientação à Representação. em cada operação (GET, POST, PUT etc.) um estado ou representação de um recurso é passado ou recebido. Em HTTP, essa representação pode ser JSON, XML, texto ou outros. Cada tipo de conteúdo compartilhado é associado a um “MIME type”. Uma mesma URI pode transferir conteúdo em XML ou JSON.
  • Ausência de estado. isso quer dizer que o servidor não guarda estado algum sobre o cliente. Se houver necessidade de algum tipo de sessão, o cliente será responsável por ela.
  • HATEOAS (Hypermedia As The Engine Of Application State). em uma solução centrada em documentos, cada documento pode conter referências para a próxima interação com o servidor. Imagine que você está consultando uma lista grande de clientes. Na primeira transferência de estado, pode haver um link para obtenção da próxima “pagina” contendo mais informações de clientes.

Seguindo esses princípios, conseguimos ter soluções com comportamentos bem definidos, escaláveis e mais facilmente interoperáveis já que consumir uma URL é algo facilmente realizado por qualquer cliente HTTP..

Um serviço Restful é uma aplicação construída dentro dos princípios explicados. Existe uma API Java conhecida por JAX-RS que pretende trazer a mesma facilidade para construção de serviços Restful que JAX-WS traz para a construção de WebServices.

Vamos agora examinar um exemplo muito simples de construção de serviço Restful utilizando o Apache CXF e Apache Camel. No nosso exemplo, o CXF é o responsável pela execução do servidor HTTP, características de transporte e ciclo de vida do serviço. O Apache Camel será a implementação do serviço gerênciado pelo CXF. Vamos dar uma olhada no serviço HelloWorldServiceRest na listagem 1.


@Path("/helloworldservice")
public class HelloWorldServiceRest {

	@GET
	@Path("/hello")
	@Produces("application/json")
	public String hello(@QueryParam("nome") String name) {
		return null;
	}

}
Listagem 1. Interface do Serviço Restful

É bem simples. Vemos uma primeira anotação @Path, determinando parte da url que dá acesso ao nosso serviço. Uma operação chamada “hello” anotada com @GET indicando que o verbo GET é suportado. @Produces indica o MIME type do retorno desse método. @QueryParam captura o parâmetro nome passado na URL. Veja um exemplo de chamada dessa operação que pode ser facilmente testado em um navegador da internet: http://localhost:8090/hello/helloworldservice/hello?nome=John.

Na listagem 2 vemos o nosso arquivo de configuração do Spring que inicia o nosso serviço no endereço físico “http://localhost:8090/hello”. Através do namespace cxf, temos acesso ao bean rsServer que utiliza a classe da listagem 1 para iniciar nosso serviço na porta configurada.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xsi:schemaLocation="
    	http://camel.apache.org/schema/spring 
        http://camel.apache.org/schema/spring/camel-spring.xsd
    	http://camel.apache.org/schema/cxf 
        http://camel.apache.org/schema/cxf/camel-cxf.xsd
		http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
		http://cxf.apache.org/jaxws
		http://cxf.apache.org/schemas/jaxws.xsd" >

	<cxf:rsServer id="server" address="http://localhost:8090/hello" 
    serviceClass="br.com.devmedia.helloworldservice
    .HelloWorldServiceRest"></cxf:rsServer>       
    <bean id="routeBuilder" 
    class="br.com.devmedia.helloworldservice.camel.HelloWorldServiceRouteBuilder" />
	<camelContext xmlns="http://camel.apache.org/schema/spring">
          <routeBuilder ref="routeBuilder" />
    </camelContext>
	
</beans>
Listagem 2. Arquivo de configuração do Spring

Reparem que temos também o camelContext, responsável por gerenciar a execução das rotas. No nosso caso especial, as rotas dizem respeito à implementação do serviço e estão descritas na classe br.com.devmedia.helloworldservice.camel.HelloWorldServiceRouteBuilder. Veja a listagem 3.


from("cxfrs:bean:server")
.process(new Processor() {

	@Override
	public void process(Exchange exchange) throws Exception {
        Message inMessage = exchange.getIn();                        
        String operationName = inMessage.getHeader(CxfConstants.
        OPERATION_NAME, String.class);
        MessageContentsList list = exchange.getIn().getBody(
        org.apache.cxf.message.MessageContentsList.class);
        org.apache.cxf.message.Message cxfMessage = inMessage.getHeader(
        CxfConstants.CAMEL_CXF_MESSAGE, org.apache.cxf.message.Message.class);
        ServletRequest request = (ServletRequest) cxfMessage.get("HTTP.REQUEST");
        String path = inMessage.getHeader(Exchange.HTTP_PATH, String.class);
        if ("hello".equals(operationName)) {
        	String nome = request.getParameter("nome");
        	if (nome == null) {
                Response r = Response.status(404).
                entity("Nome nao pode ser nulo " + path).build();
                throw new WebApplicationException(r);
        	} else {
	        	exchange.getOut().setBody("Hello " + nome);
        	}
        }
}
});
Listagem 3. Builder para rotas do Camel

A rota inicia-se com from(“cxfrs:bean:server”). Isso quer dizer que estamos consumindo qualquer tipo de dado que vier do bean server, que é o id do cxf:rsServer. Mas não estamos, de fato, interessados em qualquer conteúdo. Um pouco mais abaixo, obtemos o nome da operação que foi invocada pelo cliente através do “header” da mensagem encapsulada pelo apache Camel dentro do objeto exchange.

Reparem que para implementarmos a lógica da operação “hello” da Listagem 1, basta fazermos “if “hello”.equals(operationName)”. A nossa lógica é bem simples: apenas retornamos “Hello” concatenado ao nome passado por parâmetro. Se o nome for nulo, retornamos status 404. O resultado deve ser passado de volta ao camel, através do exchange.getOut().setBody(..).

Na listagem 4 veremos um exemplo de código de cliente para esse serviço.


WebClient client = WebClient.create(
"http://localhost:8090/hello/helloworldservice");
client.accept("application/json").type("application/json").path("/hello")
.query("nome", "John");
String result = client.get(String.class);
Assert.assertEquals("Hello John", result);
Listagem 4. Cliente para serviço Restful

Na listagem 4 fica claro como é fácil interagir com esse tipo de serviço. A classe WebClient faz parte do framework apache CXF. Através dela configuramos o endereço físico, o MIME type das mensagens que transmitimos e aceitamos os parâmetros (nesse caso “nome”) e obtemos o resultado. Existem outros métodos interessantes nessa classe que o leitor deve olhar com mais calma.

Esse exemplo simples demonstrou como é fácil darmos início a um projeto de serviço Restful se usarmos o suporte e os frameworks corretos. Para melhor entendimento do que foi dito sobre REST e RESTFUL, recomendo o excelente livro RESTful Java with JAX-RS escrito pelo grande Bill Burke. É uma verdadeira aula de como construir uma infra-estrutura SOA baseada em ideias relativamente simples.