Preloader image

Definir um serviço REST é muito fácil, simplesmente adicionamos a anotação @Path para a classe, então definimos nos métodos, o método HTTP para usar (@GET, @POST, …).

O Código

O serviço REST: @Path, @Produces, @Consumes

Aqui nós vemos um bean que usa as anotações @Path, @Produces e @Consumes. A anotação @Path identifica o modelo de caminho URI ao qual o recurso responde e é especificado no nível de classe de um recurso. O valor da anotação @Path é um modelo de caminho de URI parcial relativo ao URI de base do servidor no qual o recurso está implementado, o contexto raiz do WAR e o padrão de URL para o qual o servlet auxiliar Jersey responde. A anotação @Produces é usada para especificar os tipos de mídia MIME ou representações que um recurso pode produzir e enviar de volta ao cliente. Se @Produces for aplicado no nível da classe, todos os métodos em um recurso podem produzir os tipos MIME especificados por padrão. Se for aplicado no nível de método, substitui quaisquer anotações @Produces aplicadas no nível da classe. A anotação @Consumes é usada para especificar quais tipos de mídia MIME de representações um recurso pode aceitar ou consumir do cliente. Se @Consumes for aplicado no nível da classe, todos os métodos de resposta aceitarão os tipos MIME especificados por padrão. Se @Consumes for aplicado no nível do método, ele substituirá qualquer anotação @Consumes aplicadas no nível da classe.

Na realidade linhas:

@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })

são opcionais, uma vez que é a configuração padrão. E essas linhas, podem ser configuradas pelo método também, se você precisar para ser mais preciso.

@Path("/greeting")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public class GreetingService {
    @GET
    public Response message() {
        return new Response("Hi REST!");
    }

    @POST
    public Response lowerCase(final Request message) {
        return new Response(message.getValue().toLowerCase());
    }
}

Testando

Teste para o serviço JAXRS

O teste utiliza o Arquillian com o adaptador TomEE embedded, assim o serviço REST roda em um TomEE real.

O método @Deployment cria rapidamente a aplicação web a ser implantada com as classes deste exemplo. Você pode adicionar sua Aplicação REST e um web.xml também. testable = false executa os métodos de teste como cliente da aplicação implantada, e @ArquillianResource injeta a URL base dela.

Finalmente para testá-lo, usamos a API cliente cxf, para chamar o serviço REST em métodos get() e post(). Os cabeçalhos Accept e Content-Type selecionam JSON ou XML.

O contêiner é configurado em src/test/resources/arquillian.xml: httpPort com valor -1 inicia o TomEE em uma porta aleatória.

package org.superbiz.rest;

import org.apache.cxf.jaxrs.client.WebClient;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;

import jakarta.ws.rs.core.MediaType;
import java.io.IOException;
import java.net.URL;

import static org.junit.Assert.assertEquals;

@RunWith(Arquillian.class)
public class GreetingServiceTest {

    @ArquillianResource
    private URL base;

    @Deployment(testable = false)
    public static WebArchive app() {
        return ShrinkWrap.create(WebArchive.class).addClasses(GreetingService.class, Request.class, Response.class);
    }

    @Test
    public void getXml() throws IOException {
        final String message = WebClient.create(base.toExternalForm()).path("greeting/")
                .accept(MediaType.APPLICATION_XML_TYPE)
                .get(String.class);
        assertEquals("<response><value>Hi REST!</value></response>", message.replaceAll("<\\?[^>]*\\?>", "").trim());
    }

    @Test
    public void postXml() throws IOException {
        final String message = WebClient.create(base.toExternalForm())
                .path("greeting/")
                .type(MediaType.APPLICATION_XML_TYPE)
                .accept(MediaType.APPLICATION_XML_TYPE)
                .post("<request><value>Hi REST!</value></request>", String.class);
        assertEquals("<response><value>hi rest!</value></response>", message.replaceAll("<\\?[^>]*\\?>", "").trim());
    }

    @Test
    public void getJson() throws IOException {
        final String message = WebClient.create(base.toExternalForm())
                .path("greeting/")
                .accept(MediaType.APPLICATION_JSON_TYPE)
                .get(String.class);
        assertEquals("{\"value\":\"Hi REST!\"}", message);
    }

    @Test
    public void postJson() throws IOException {
        final String message = WebClient.create(base.toExternalForm())
                .path("greeting/")
                .type(MediaType.APPLICATION_JSON_TYPE)
                .accept(MediaType.APPLICATION_JSON_TYPE)
                .post(new Request("Hi REST!"), String.class);
        assertEquals("{\"value\":\"hi rest!\"}", message);
    }
}

#Executando

Executar o exemplo é bastante simples. No diretório ``rest-xml-json'' executa:

$ mvn clean install

Que deve criar saída como a seguinte.

Running org.superbiz.rest.GreetingServiceTest
INFO: Starting TomEE from: /tmp/arquillian-apache-tomee-21989
INFO: Starting Servlet engine: [Apache Tomcat/11.0.25]
INFO: Starting ProtocolHandler ["http-nio-52850"]
INFO: Configuring enterprise application: /path/to/tomee/examples/rest-xml-json/target/tomee-embedded/0/2f767e7a-173c-40c2-b7e1-78e2e1570f59
INFO: Enterprise application "/path/to/tomee/examples/rest-xml-json/target/tomee-embedded/0/2f767e7a-173c-40c2-b7e1-78e2e1570f59" loaded.
INFO: Deployed Application(path=/path/to/tomee/examples/rest-xml-json/target/tomee-embedded/0/2f767e7a-173c-40c2-b7e1-78e2e1570f59)
INFO: REST Application: http://localhost:52850/2f767e7a-173c-40c2-b7e1-78e2e1570f59/         -> org.apache.openejb.server.rest.InternalApplication
INFO:      Service URI: http://localhost:52850/2f767e7a-173c-40c2-b7e1-78e2e1570f59/greeting -> Pojo org.superbiz.rest.GreetingService
INFO:               GET http://localhost:52850/2f767e7a-173c-40c2-b7e1-78e2e1570f59/greeting ->      Response message()
INFO:              POST http://localhost:52850/2f767e7a-173c-40c2-b7e1-78e2e1570f59/greeting ->      Response lowerCase(Request)
INFO: Undeploying app: /path/to/tomee/examples/rest-xml-json/target/tomee-embedded/0/2f767e7a-173c-40c2-b7e1-78e2e1570f59
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.926 s -- in org.superbiz.rest.GreetingServiceTest
Results:

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0