@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
REST Simple
Definir un servicio REST es bastante fácil, simplemente agregue la anotación @Path a una clase luego defina en los métodos el método HTTP a usar (@GET, @POST, …).
El Código
El servicio REST: @Path, @Produces, @Consumes
Aquí vemos un bean que usa las anotaciones @Path, @Produces y @Consumes. La anotación @Path identifica la plantilla de ruta de URI a la que responde el recurso y se especifica en el nivel de clase de un recurso. El valor de la anotación @Path es una plantilla de ruta de URI parcial relativa al URI base del servidor en el que se implementa el recurso, la raíz de contexto del WAR y el patrón de URL al que responde el servlet auxiliar de Jersey. La anotación @Produces se utiliza para especificar los tipos de medios MIME o las representaciones que un recurso puede producir y enviar al cliente. Si @Produces se aplica en el nivel de clase, todos los métodos de un recurso pueden producir los tipos MIME especificados de forma predeterminada. Si se aplica a nivel de método, sobrescribe cualquier @Produces anotaciones aplicadas a nivel de clase. La anotación @Consumes se utiliza para especificar qué tipos de representaciones de medios MIME puede aceptar o consumir un recurso del cliente. Si se aplica @Consumes a nivel de clase, todos los métodos de respuesta aceptan los tipos MIME especificados de forma predeterminada. Si @Consumes se aplica a nivel de método, anula cualquier @Consumes anotaciones aplicadas a nivel de clase.
En realidad líneas:
son opcionales ya que es la configuración predeterminada. Y estas líneas pueden configurarse también por método si necesita ser más 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());
}
}
Pruebas
Prueba del servicio JAXRS
La prueba usa Arquillian con el adaptador TomEE embedded, así el servicio REST se ejecuta en un TomEE real.
El método @Deployment crea sobre la marcha la aplicación web a desplegar con las clases de este ejemplo. También puede agregar su aplicación REST y un web.xml. testable = false ejecuta los métodos de prueba como cliente de la aplicación desplegada, y @ArquillianResource inyecta su URL base.
Finalmente para probarlo usamos la API del cliente cxf para llamar al servicio REST en métodos get() y post(). Las cabeceras Accept y Content-Type seleccionan JSON o XML.
El contenedor se configura en src/test/resources/arquillian.xml: httpPort con valor -1 inicia TomEE en un puerto aleatorio.
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);
}
}
#Running
Ejecutar el ejemplo es bastante simple. En el directorio rest-xml-json
run:
$ mvn clean install
Lo que debería crear una salida como la siguiente.
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