REST y como hacer con jQuery un PUT hacia Spring MVC

3
26230

Creación: 10-02-2011

Índice de contenidos

1.Introducción
2. Entorno
3.El código del cliente con jQuery
4.El código del servidor con Spring MVC
5.¿Y qué pasa si mi navegador no soporta el método PUT?
5.1.El código del cliente con jQuery
5.2.El filtro en el web.xml
5.3.El controlador de Spring MVC
6.Conclusiones
7. Sobre el autor


1. Introducción

Según la Wikipedia, REST (REpresentational State Transfer) es un estilo de arquitectura de software para sistemas hipermedia distribuidos como la World Wide Web. Básicamente consiste en una serie de servidores y de clientes, donde los clientes inician
peticiones a los servidores, estos las procesan y devuelven la respuesta correspondiente. Tanto en las peticiones como en las respuestas se transmite una representación de los recursos hipermedia.

Podríamos decir que REST es un mecanismo para el intercambio y manipulación de recursos a través de Internet. Es semejante a los Web Services, pero no usa un protocolo concreto para el intercambio de la información (los Web Services usan SOAP), de manera que podemos intercambiar información en formato HTML, XML, JSON, …

Inicialmente REST se describe en el contexto de HTTP (aunque no se limita sólo a este protocolo), por lo que se aprovecha de todas sus características: URIs, tipos de media, sesiones, seguridad, cache, …

Las operaciones típicas que podemos hacer con REST son:

  • GET, para recuperar un recurso. Es idempotente, es decir si la ejecutamos más de una vez siempre devuelve el mismo recurso.
  • POST, para añadir recursos. No es idempotente, es decir si la ejecutamos dos veces estaremos añadiendo dos recursos.
  • PUT, para modificar un recurso. Es idempotente, si la ejecutamos más de una vez la modificación es siempre la misma (por ejemplo cambiar el nombre de una persona en una agenda).
  • DELETE, para borrar un recurso. Es idempotente, si lo ejecutamos más de una vez el resultado es siempre el mismo: el recurso deja de estar en el sistema (la primera vez se borra realmente, las siguientes veces simplemente se ignora la petición, pero no da error).

Otros verbos que tenemos disponibles son:

  • HEAD, para pedir un recurso sin recuperarlo, nos sirve para saber si existe o para traer metainformación sobre el recurso.
  • OPTIONS, para preguntarle a un servidor sobre que otros verbos son aplicables a un recurso determinado.
  • PATH, es de reciente adopción (en el 2010), es un intento de expresar de forma estándar actualizaciones parciales de un recurso.

 

El problema surge cuando usamos REST con HTTP donde sólo están soportados los verbos GET y POST. En este tutorial vamos a ver como usando el soporte de REST que ofrece Spring MVC, vamos a hacer un PUT con jQuery desde el navegador, transmitiendo un objeto codificado en JSON.


2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 17′ (2.8 GHz Intel i7, 8GB DDR3 SDRAM, 256GB Solid State Drive).
  • NVIDIA GeForce GT 330M with 512MB
  • Sistema Operativo: Mac OS X Snow Leopard 10.6.6
  • JDK 1.6.0_22
  • Spring 3.0.5.RELEASE
  • jQuery 1.5
  • Jackson 1.6.4


3. El código del cliente con jQuery

jQuery tiene un soporte bastante bueno para peticiones AJAX, de forma que podemos encontrar métodos como:

  • $.ajax(), es el método de más bajo nivel donde podemos especificar todas las opciones, incluido el tipo de la comunicación (GET/POST/PUT/DELETE) con el atributo type.
  • $.getJSON(), es una abreviatura de la anterior para recuperar un objeto JSON con una petición GET.
  • $.post(), es una abreviatura de la primera para para hacer peticiones POST.

Así, si queremos hacer un PUT de un JSON para mandar una actualización de una Persona (Persona es un recurso REST), podríamos hacer en JavaScript algo como:

$.ajax("rest/addressBook/" + personId, {
    type : "PUT",
    data : JSON.stringify(person),
    contentType : "application/json",
    success : function() {
        // Acciones a realizar cuando la petición ha terminado con éxito
        ...
    }
});

 

Simplemente destacar como en el primer parámetro estamos indicando la URL y dentro de está va el id del recurso que vamos a modificar. También es importante el uso del atributo contentType para indicar en las cabeceras de la petición que el contenido del mensaje es un objeto JSON.


4. El código del servidor con Spring MVC

En el servidor vamos a indicar que queremos recibir una petición PUT, y que se debe deserialzar un objeto JSON (para más información sobre la deserialización de objetos JSON podéis ver el tutorial
http://adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=jackson-deserialize-with-constructor).

@Controller
@RequestMapping("/addressBook")
public class AddressBookController {

    private final AddressBook addressBook;

    @Autowired
    public AddressBookController(AddressBook addressBook) {
        this. addressBook = addressBook;
    }

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<Person> getPersons() {
        return addressBook.getPersons();
    }

    @RequestMapping(value = "/{personId}", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void updatePerson(@PathVariable Integer personId, @RequestBody Person person) {
        addressBook.updatePerson(personId, person);
    }
}

 

Simplemente resaltar como en el método updatePerson estamos indicando con la anotación code>@RequestMapping</code que el método que esperamos es PUT. Y como marcamos el parámetro person con la anotación code>@RequestBody</code para indicar a Spring MVC que debe deserializar el contenido de la request en un objeto Person que nos pasará como argumento del parámetro.


5. ¿Y qué pasa si mi navegador no soporta el método PUT?

Puede ocurrir que estemos usando navegadores un poco antiguos que sólo soportan los métodos GET y POST. En tal caso podemos usar el soporte de Spring MVC para simular los verbos PUT y DELETE a través de una petición POST. Para ello que haremos será lanzar un POST con un parámetro en la request que indica el verbo que realmente queremos ejecutar. Luego usaremos un filtro de Spring MVC para hacer la conversión y llamar al método correcto del controlador. Veamos un ejemplo:


5.1. El código del cliente con jQuery

$.post("rest/addressBook/" + personId, {
    _method : "PUT",
    person : JSON.stringify(person)
}, function() {
    // Acciones a realizar cuando la petición ha terminado con éxito
    ...
});

 

Se puede ver que la llamada es muy similar a la que hacíamos antes. Destacamos que hemos cambiado $.ajax() por $.post(), y sobre todo que ahora estamos metiendo la
información en la request usando dos parámetros: _method para indicar el verbo REST que queremos invocar, y person donde irá codificado en JSON nuestro recurso (la persona que queremos actualizar).


5.2. El filtro en el web.xml

Para configurar el filtro en el web.xml simplemente tenderemos que añadir:

<filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <servlet-name>addressBookDispatcherServlet</servlet-name>
</filter-mapping>

 

Donde addressBookDispatcherServlet es el nombre del DispatcherServlet de Spring MVC.


5.3. El controlador de Spring MVC

Respecto al ejemplo que veíamos antes sólo cambiaría el método updatePerson, y quedaría de la siguiente manera:

@RequestMapping(value = "/{personId}", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void updateStory(@PathVariable Integer personId, @RequestParam Person person) {
    addressBook.updateStory(personId, person);
}

 

Ahora necesitamos una pieza nueva, un PropertyEditor para la clase Person, porque como el JSON en vez de venir directamente en el cuerpo de la request viene en un parámetro, Spring no va a saber hacer la conversión de la cadena que contiene el JSON a la clase Person. Es tan fácil como añadir la siguiente clase:

public class PersonEditor extends PropertyEditorSupport {

    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        try {
            Person person = mapper.readValue(text, Person.class);
            setValue(person);
        } catch (IOException e) {
            throw new IllegalArgumentException("Cannot convert '" + text + "' to " + Person.class.getName(), e);
        }
    }
}

 

Es importante destacar que esta clase tiene que estar en el mismo paquete que la clase Person, y que por convención el nombre tiene que ser el del objeto que queremos convertir (Person) más el sufijo Editor.

6. Conclusiones

REST se está imponiendo como una alternativa más que viable a los Web Services con SOAP, ya que es más sencillo y la comunicación más ligera, además de que nos podemos aprovechar de todas las características de HTTP, por ejemplo mantenimiento de sesión y
seguridad (que son dos cosas que desde luego no las obtenemos directamente con los Web Services tradicionales).

De esta manera usar este tipo de arquitectura puede ser muy interesante cuando:

  • Queremos un gran número de usuarios concurrente. REST no pude venir muy bien ya que toda la lógica de presentación la podemos hacer en el navegador del cliente con JavaScript (nos aprovechamos de toda la potencia de la máquina cliente, que ha día
    de hoy es mucha), de forma que el servidor sólo procesa las peticiones que son realmente de negocio, disminuyendo así el número de peticiones que se hacen al servidor. También se consigue mejorar el uso de memoria, que ya habrá muchos menos objetos en la sesión del usuario la mantener toda la lógica de interfaz en el cliente
    (usamos la memoria del cliente).
  • Vamos a consumir la información desde un conjunto heterogéneo de dispositivos, por ejemplo si queremos hacer una aplicación web, otra para el iPhone, otra para el Android, integrar con otros servicios, …

7. Sobre el autor

Alejandro Pérez García, Ingeniero en Informática (especialidad de Ingeniería del Software) y Certified ScrumMaster

Socio fundador de Autentia (Desarrollo de software, Consultoría, Formación)

mailto:alejandropg@autentia.com

Autentia Real Business Solutions S.L. – «Soporte a Desarrollo»

http://www.autentia.com

 

Alejandro es socio fundador de Autentia y nuestro experto en Java EE, Linux y optimización de aplicaciones empresariales. Ingeniero en Informática y Certified ScrumMaster. Seguir @alejandropgarci Si te gusta lo que ves, puedes contratarle para darte ayuda con soporte experto, impartir cursos presenciales en tu empresa o para que realicemos tus proyectos como factoría (Madrid). Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.

3 COMENTARIOS

  1. Buen tutorial, desde mi punto de vista es bueno que existan diferentes alternativas para hacer una misma cosa: en este caso, web services.

  2. Muy buen tutorial. Mo podrias indicar como podria con jquery trabajar el json que optengo con el rest para que pueda tener todos los datos sin tener un input de cada campo. Te doy un ejemplo porque no se si me exprese bien.
    En un caso tendría un objeto factura que obtengo mediante rest al cual se le asigna imágenes (en el objeto el nombre hacia la url del ftp) mediante drag and drop de div que muestran sus thumbnails.
    Si en el html no tengo el formulario sino que las imágenes como podría agregar el json de factura a el html para tomarlo luego junto con la lista de url correspondiente a las imágenes?

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad