JAX-RS é apenas uma API!

JAX-RS é apenas uma API!

1. Visão geral

O paradigma REST já existe há alguns anos e ainda está recebendo muita atenção.

Uma API RESTful pode ser implementada em Java de várias maneiras: você pode usar Spring, JAX-RS ou pode apenas escrever seus próprios servlets simples, se for bom e corajoso o suficiente. Tudo o que você precisa é a capacidade de expor os métodos HTTP - o restante é sobre como você os organiza e como orienta o cliente ao fazer chamadas para sua API.

Como você pode ver no título, este artigo abordará o JAX-RS. Mas o que significa "apenas uma API"? Isso significa que o foco aqui é esclarecer a confusão entre o JAX-RS e suas implementações e oferecer um exemplo de como é um aplicativo da Web JAX-RS adequado.

2. Inclusão em Java EE

O JAX-RS nada mais é do que uma especificação, um conjunto de interfaces e anotações oferecidas pelo Java EE. E então, é claro, temos as implementações; alguns dos mais conhecidos sãoRESTEasy eJersey.

Além disso, se você decidir construir um servidor de aplicativos compatível com JEE, os funcionários da Oracle dirão que, entre muitas outras coisas, seu servidor deve fornecer uma implementação JAX-RS para os aplicativos implementados usarem. É por isso que é chamado de Java Enterprise EditionPlatform.

Outro bom exemplo de especificação e implementação éJPAeHibernate.

2.1. Guerras leves

Então, como tudo isso nos ajuda, os desenvolvedores? A ajuda é que nossas implementáveis ​​podem e devem ser muito pequenas, permitindo que o servidor de aplicativos forneça as bibliotecas necessárias. Isso se aplica também ao desenvolver uma API RESTful: o artefato final não deve conter nenhuma informação sobre a implementação JAX-RS usada.

Claro, podemos fornecer a implementação (here é um tutorial para RESTeasy). Porém, não podemos mais chamar nosso aplicativo de "Java EE app". Se amanhã alguém vier e disser “Ok, time to switch to Glassfish or Payara, JBoss became too expensive!“, talvez possamos fazer isso, mas não será um trabalho fácil.

Se fornecermos nossa própria implementação, precisamos garantir que o servidor saiba excluir a sua própria - isso geralmente acontece com um arquivo XML proprietário dentro da implementação. Desnecessário dizer que esse arquivo deve conter todos os tipos de tags e instruções das quais ninguém sabe nada, exceto os desenvolvedores que deixaram a empresa há três anos.

2.2. Sempre conheça seu servidor

Dissemos até agora que devemos aproveitar as vantagens da plataforma que nos é oferecida.

Antes de decidir sobre o servidor a ser usado, devemos ver qual implementação JAX-RS (nome, fornecedor, versão e bugs conhecidos) ela fornece, pelo menos para ambientes de produção. Por exemplo, Glassfish vem com Jersey, enquanto Wildfly ou Jboss vêm com RESTEasy.

Isso, é claro, significa um pouco de tempo gasto em pesquisa, mas deve ser feito apenas uma vez, no início do projeto ou ao migrá-lo para outro servidor.

3. Um exemplo

Se você quiser começar a jogar com JAX-RS, o caminho mais curto é: ter um projeto de webapp Maven com a seguinte dependência empom.xml:


    javax
    javaee-api
    7.0
    provided

Estamos usando o JavaEE 7 porque já existem muitos servidores de aplicativos implementando-o. Esse jar de API contém as anotações que você precisa usar, localizadas no pacotejavax.ws.rs. Por que o escopo é "fornecido"? Porque este jar não precisa estar na compilação final também - precisamos dele no tempo de compilação e é fornecido pelo servidor para o tempo de execução.

Depois que a dependência é adicionada, primeiro temos que escrever a classe de entrada: uma classe vazia que estendejavax.ws.rs.core.Applicatione é anotada comjavax.ws.rs.ApplicationPath:

@ApplicationPath("/api")
public class RestApplication extends Application {
}

Definimos o caminho de entrada como sendo/api. Quaisquer outros caminhos que declararmos para nossos recursos, eles serão prefixados com/api.

A seguir, vamos ver um recurso:

@Path("/notifications")
public class NotificationsResource {
    @GET
    @Path("/ping")
    public Response ping() {
        return Response.ok().entity("Service online").build();
    }

    @GET
    @Path("/get/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getNotification(@PathParam("id") int id) {
        return Response.ok()
          .entity(new Notification(id, "john", "test notification"))
          .build();
    }

    @POST
    @Path("/post/")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response postNotification(Notification notification) {
        return Response.status(201).entity(notification).build();
    }
}

Temos um ponto de extremidade de ping simples para chamar e verificar se nosso aplicativo está em execução, um GET e um POST para uma notificação (este é apenas um POJO com atributos, mais getters e setters).

Implemente essa guerra em qualquer servidor de aplicativos que implemente o JEE7 e os seguintes comandos funcionarão:

curl http://localhost:8080/simple-jaxrs-ex/api/notifications/ping/

curl http://localhost:8080/simple-jaxrs-ex/api/notifications/get/1

curl -X POST -d '{"id":23,"text":"lorem ipsum","username":"johana"}'
  http://localhost:8080/simple-jaxrs-ex/api/notifications/post/
  --header "Content-Type:application/json"

Onde simple-jaxrs-ex é a raiz de contexto do aplicativo da web.

Isso foi testado com o Glassfish 4.1.0 e o Wildfly 9.0.1.Final. Observe que os dois últimos comandos não funcionarão com Glassfish 4.1.1, devido ao bug dethis. Aparentemente, é um problema conhecido nesta versão do Glassfish, em relação à serialização do JSON (se você tiver que usar esta versão do servidor, terá que gerenciar o empacotamento JSON por conta própria)

4. Conclusão

No final deste artigo, lembre-se de que o JAX-RS é uma API poderosa e a maioria (se não todas) de tudo o que você precisa já foi implementada pelo seu servidor da web. Não há necessidade de transformar sua implementável em uma pilha incontrolável de bibliotecas.

Este artigo apresenta um exemplo simples e as coisas podem ficar mais complicadas. Por exemplo, você pode escrever seus próprios marshalers. Quando necessário, procure tutoriais que resolvam seu problema com JAX-RS, não com Jersey, Resteasy ou outra implementação concreta. É muito provável que seu problema possa ser resolvido com uma ou duas anotações.