1 oct. 2013

REST en Java

Hoy toca probar REST y como (de bien) se lleva con Java. Para ello vamos a ponernos un poco en situación.

¿Qué es REST?

REST son las siglas de REpresentational State Transfer, es un estilo de arquitectura de aplicaciones software que está basado en estándares web y en protocolos HTTP. En esta arquitectura todo son recursos, y se puede acceder a estos recursos usando métodos estándares de HTTP.

En una arquitectura REST normalmente se dispone de un servidor REST que ofrece acceso a los recursos y un cliente que accede y modifica estos recursos. Cada uno de los recursos debe tener soporte a las operaciones HTTP más comunes, que comentaré más adelante, y se identifican de manera global, normalmente a través de URIs.


La arquitectura REST permite que los recursos tengan distintas representaciones (texto, XML, JSON, RSS,...) por lo que el cliente puede solicitar la representación que más le convenga mediante el protocolo HTTP.


Los métodos HTTP que soporta REST son los habitules de peticiones estándar HTTP, PUT, GET, POST y DELETE. Estas operaciones se podrían explicar de la siguiente manera:

  • PUT: Crea un nuevo recurso, por lo que nunca se podrá realizar una consulta a través de este método.
  • GET: acceso de lectura al recurso, por lo que nunca se puede modificar usando este método.
  • POST: Actualiza un recurso existente o crea uno nuevo.
  • DELETE: Elimina un recurso.
Entonces,

¿Cómo aplicar la arquitectura REST en Java?

Pues usando la implementación de referencia JAX-RS de Java con Jersey. Esta implementación de referencia nos permite crear servicios web RESTful basados en métodos HTTP y el concepto REST. 

Normalmente se define la URI base de todos los servicios, el tipo MIME que soporta (XML, Texto, JSON, ...) y el conjunto de operaciones HTTP (PUT, GET, POST y DELETE). Para esto existen una serie de anotaciones que nos simplifican la vida bastante. Estas anotaciones son las siguientes:


Anotación Descripción
@PATH(ruta) Establece la ruta base + la ruta definida. La ruta base está basada en la ruta de acceso a la aplicación, el servlet y el patrón URL definido en el descriptor de despliegue web.xml.
@POST Indica que el método atenderá a peticiones HTTP POST
@GET Indica que el método atenderá a peticiones HTTP GET
@PUT Indica que el método atenderá a peticiones HTTP PUT
@DELETE Indica que el método atenderá a peticiones HTTP DELETE
@Produces(tipo [, más-tipos ]) @Produces define que tipo MIME se generará en la llamada al metodo con la anotación @GET.
@Consumes(tipo [, más-tipos]) @Consumes define que tipo MIME consumirá el método.
@PathParam Se usa para inyectar parámetros desde la URL a los parámetros del método.


Se puede consultar más información acerca de Jersey en la página oficial http://jersey.java.net

Creación de un proyecto REST con Maven

Para crear un proyecto REST con maven usando la implementación de Jersey deberemos ejecutar el siguiente comando de maven:

mvn archetype:generate                              \
-DarchetypeArtifactId=jersey-quickstart-grizzly2    \
-DarchetypeGroupId=org.glassfish.jersey.archetypes  \
-DinteractiveMode=false                             \
-DgroupId=com.javiserrano                           \
-DartifactId=rest-service                           \
-Dpackage=com.javiserrano                           \
-DarchetypeVersion=2.3.1

Esto nos creará un proyecto con la estructura necesaria. El contenido de la carpeta rest-service generada será el de un proyecto Maven estándar, con un archivo pom.xml, que será similar al siguiente:


    4.0.0

    com.javiserrano
    rest-service
    jar
    1.0-SNAPSHOT
    rest-service

    
        
            
                org.glassfish.jersey
                jersey-bom
                ${jersey.version}
                pom
                import
            
        
    

    
        
            org.glassfish.jersey.containers
            jersey-container-grizzly2-http
        
        
        
            junit
            junit
            4.9
            test
        
        
            org.glassfish.jersey.core
            jersey-client
            test
        
    

    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                2.5.1
                true
                
                    1.6
                    1.6
                
            
            
                org.codehaus.mojo
                exec-maven-plugin
                1.2.1
                
                    
                        
                            java
                        
                    
                
                
                    com.javiserrano.Main
                
            
        
    

    
        2.3.1
        UTF-8
    

Además creará dos clases Java, una que es el servicio REST que se llama MyResource que tendrá el siguiente contenido:

package com.javiserrano;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("myresource")
public class MyResource {

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        return "Got it!";
    }
}

Y otra más que contiene un método main que nos sirve para ejecutar el contenedor, configurar y desplegar la aplicación en el contenedor.


Además se crea una clase para poder testear el servicio REST creado MyResourceTest con el siguiente contenido:


package com.javiserrano;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;

import org.glassfish.grizzly.http.server.HttpServer;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class MyResourceTest {

    private HttpServer server;
    private WebTarget target;

    @Before
    public void setUp() throws Exception {
        // start the server
        server = Main.startServer();
        // create the client
        Client c = ClientBuilder.newClient();

        // uncomment the following line if you want to enable
        // support for JSON in the client (you also have to uncomment
        // dependency on jersey-media-json module in pom.xml and Main.startServer())
        // --
        // c.configuration().enable(new org.glassfish.jersey.media.json.JsonJaxbFeature());

        target = c.target(Main.BASE_URI);
    }

    @After
    public void tearDown() throws Exception {
        server.stop();
    }

    /**
     * Test to see that the message "Got it!" is sent in the response.
     */
    @Test
    public void testGetIt() {
        String responseMsg = target.path("myresource").request().get(String.class);
        assertEquals("Got it!", responseMsg);
    }
}

Para comprobar que funciona, ejecutaremos el siguiente comando maven:


mvn clean test

Que generará una salida por consola similar a la siguiente:

[INFO] Scanning for projects... 
[INFO]
[INFO] ------------------------------------------------------------------------ 
[INFO] Building rest-service 1.0-SNAPSHOT 
[INFO] ------------------------------------------------------------------------ 
[INFO]  
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ rest-service --- 
[INFO] Deleting .../rest-service/target 
[INFO]  
[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ rest-service --- 
[debug] execute contextualize 
[INFO] Using 'UTF-8' encoding to copy filtered resources. 
[INFO] skip non existing resourceDirectory .../rest-service/src/main/resources 
[INFO]  
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ rest-service --- 
[INFO] Compiling 2 source files to .../rest-service/target/classes 
[INFO]  
[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ rest-service --- 
[debug] execute contextualize 
[INFO] Using 'UTF-8' encoding to copy filtered resources. 
[INFO] skip non existing resourceDirectory .../rest-service/src/test/resources 
[INFO]  
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ rest-service --- 
[INFO] Compiling 1 source file to .../rest-service/target/test-classes 
[INFO]  
[INFO] --- maven-surefire-plugin:2.10:test (default-test) @ rest-service --- 
[INFO] Surefire report directory: .../rest-service/target/surefire-reports 
------------------------------------------------------- 
Running com.javiserrano.MyResourceTest 
oct 01, 2013 2:52:07 PM org.glassfish.jersey.server.ApplicationHandler initialize 
INFO: Initiating Jersey application, version Jersey: 2.3.1 2013-09-27 07:50:09... 
oct 01, 2013 2:52:08 PM org.glassfish.grizzly.http.server.NetworkListener start 
INFO: Started listener bound to [localhost:8080] 
oct 01, 2013 2:52:08 PM org.glassfish.grizzly.http.server.HttpServer start 
INFO: [HttpServer] Started. 
oct 01, 2013 2:52:08 PM org.glassfish.grizzly.http.server.NetworkListener stop 
INFO: Stopped listener bound to [localhost:8080] 
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.895 sec 
   Results : 
   Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 
   [INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total time: 4.809s 
[INFO] Finished at: Tue Oct 01 15:52:08 CEST 2013 
[INFO] Final Memory: 13M/247M 
[INFO] ------------------------------------------------------------------------ 

Con esto ya tenemos nuestro primer servicio web RESTful.

Los fuentes de este proyecto están disponibles en http://bit.ly/18oveEQ

Creación de un proyecto JavaEE REST con Maven

Si lo que queremos es crear una aplicación web JavaEE deberemos generar el proyecto usando otro arquetipo, ejecutando el siguiente comando maven:


mvn archetype:generate                              \
-DarchetypeArtifactId=jersey-quickstart-webapp      \
-DarchetypeGroupId=org.glassfish.jersey.archetypes  \
-DinteractiveMode=false                             \
-DgroupId=com.javiserrano                           \
-DartifactId=rest-service-webapp                    \
-Dpackage=com.javiserrano                           \
-DarchetypeVersion=2.3.1

La ejecución de este comando nos generará una estructura maven estándar de proyectos para aplicaciones web JavaEE.

En este caso el archivo pom.xml será como este:


    4.0.0

    com.javiserrano
    rest-service-webapp
    war
    1.0-SNAPSHOT
    rest-service-webapp

    
        rest-service-webapp
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                2.5.1
                true
                
                    1.6
                    1.6
                
            
        
    

    
        
            
                org.glassfish.jersey
                jersey-bom
                ${jersey.version}
                pom
                import
            
        
    

    
        
            org.glassfish.jersey.containers
            jersey-container-servlet-core
            
            
        
        
    
    
        2.3.1
        UTF-8
    

Además creará un descriptor de despliegue web.xml similar al siguiente:

    
        Jersey Web Application
        org.glassfish.jersey.servlet.ServletContainer
        
            jersey.config.server.provider.packagescom.javiserrano
        1
    
    
        Jersey Web Application
        /webapi/*
    

Además genera un archivo JSP con el siguiente contenido.

<html>
<body>
    <h2>
Jersey RESTful Web Application!</h2>
<p>
<a href="webapi/myresource">Jersey resource</a>
    <p>
Visit <a href="http://jersey.java.net">Project Jersey website</a>
    for more information on Jersey!
</body>
</html>
Que permite probar el servicio REST pulsando en el enlace “Jersey resource”.
Para poder probar el funcionamiento podemos ejecutar el siguiente comando maven:
mvn package tomcat:run

Abrir un navegador y navegar a la dirección http://localhost:8080/rest-service-webapp.

Los fuentes de este proyecto están disponibles en http://bit.ly/19eAPjY

Espero que os sirva de ayuda para empezar en este mundo REST.

Un saludo y a disfrutar!!

No hay comentarios: