Category Archives: Web

Testeando y documentando REST WS con Spring REST Docs

El presente post se centra en el uso de Spring REST Docs, un componente de la suite de Spring, que tiene como objetivo facilitar la generación de documentación de servicios web tipo REST.

Esta parte de Spring se integra con Spring MVC Test para que, desde nuestros tests de unidad o de integración, podamos, a la vez que se testean los servicios web, generar una documentación en formato HTML completa, consistente y moderna con la que describir el uso de los mismos.

Qué cocinamos

El uso de servicios web es una buena manera de compartir funcionalidades entre aplicaciones, crear interacciones entre ellas e integrar diferentes usos. Es una manera sencilla y poco invasiva de compartir información y realizar peticiones de ejecución de todo tipo de servicios. Además los servicios web tipo REST son sencillos de implementar, siguen estándares bien definidos y son compatibles entre multitud de aplicaciones y tipos de tecnologías.

Uno de los principales problemas a la hora de compartir o publicar un conjunto de servicios web tipo REST para que puedan ser usados por terceros es documentarlos debidamente para que esas terceras partes conozcan como usarlos, que invocar, que entradas de datos deben usar o que salidas deben esperar. Si otros tipos de servicios similares, como los servicios web tipo SOAP tienen documentos más o menos formales y estandarizados como los WSDL, que pueden ser usados por aplicaciones de terceros para crear clientes que invoquen a nuestros servicios, practicamente de forma automática, en el caso de los servicios tipo REST, su simplicidad y fundamentos basados en tecnologías más genéricas impide o dificulta la presencia de ese tipo de formalismos (aunque existen intentos para definir formalmente este tipo de servicios de forma similar usando también XML).

Al final, lo que parece ser una ventaja del mundo de los WS tipo REST, en relación a su simplicidad, puede verse como un problema a la hora de transmitir su uso a terceros. Por este motivo, se recomiendan, además de usar una serie de estándares o buenas prácticas a la hora de desarrollar los servicios, unas buenas prácticas asimismo a la hora de documentarlos. En este sentido, Spring REST Docs es una herramienta de gran utilidad ya que permite, al mismo tiempo que se testean esos mismos servicios web, generar una documentación de calidad. Además si se siguen esas recomendaciones y buenas prácticas, tendremos una documentación útil y sencilla de transmitir a terceros para que puedan hacer uso de nuestros servicios.

Lo que hace Spring REST Docs es generar, en función de la implementación que establezcamos en su ejecución, que puede realizarse integramente dentros de los tests de unidad o integración de nuestros servicios, una documentación en texto plano que posteriormente se transformará en HTML (u otros formatos) usando un programa externo llamado Asciidoctor. Para facilitar esto, existen plug-ins para Maven que permiten ejecutar los tests y generar la documentación de forma simultánea, de tal manera que incluso si la generación de documentación falla, el test también fallará, asegurándonos así que existe una referencia consistente para ese servicio.

Ingredientes

Vamos a usar una aplicación web de prueba que implementa una serie de servicios web tipo REST para pobar los Spring REST Docs, testeando y documentando dichos servicios de forma simultanea. Para ello necesitaremos:

  • Spring Boot
  • Spring MVC
  • Spring Data
  • Spring REST Docs
  • HSQLDB
  • Log4j

Para más información acerca de las dependencias usadas (versiones, paquetes específicos etc.) se puede echar un vistazo al pom.xml que se incluye con el proyecto.

Paso a paso

Lo de siempre, una vez creado nuestro proyecto, se maveniza. Este es el aspecto del pom.xml que incluye las dependencias a las librerias de los componentes anteriores:

En este caso, como en otros expuestos en este blog, para facilitar la implementación y ejecución de la prueba, se usa Spring Boot. Para implementar una pequeña aplicacion de prueba que desarrolle una serie de servicios web con acceso a datos, se usa la integración de Spring MVC y Spring Data con Spring Boot, de esta manera podremos implementar una sencilla aplicacion de forma rápida y simple. Se usa HSQLDB como base de datos relacional embebida, que nos permitirá ejecutar las operaciones CRUD clásicas de persistencia de datos.

El resto del pom incluye, además, los plugin que se usarán para, desde Maven, ejecutar los tests y la generación de la documentación (con Asciidoctor).

1. Desarrollar la aplicación de prueba que implementa los servicios web

Vamos a desarrollar una aplicación muy sencilla que nos permita realizar las clásicas operaciones CRUD sobre una entidad concreta y poder acceder a esas operaciones mediante servicios web tipo REST. Nuestra aplicación va a realizar lo siguiente:

  • Insertar o actualizar un superheroe
  • Borrar un superheroe
  • Mostrar un superheroe
  • Mostrar la lista de superheroes

Para ello desarrollamos una aplicación por capas más o menos clásica que implemente los diferentes niveles de acceso a los datos:

  • Un POJO que representa la entidad “Superheroe”
  • Un DAO que por simplicidad solo implementará las operaciones CRUD anteriores
  • Un Controlador que implementará los servicios web

En este caso, como no hay lógica de negocio, y por simplicidad y porque el post está centrado en la generación de la documentación de los servicios web y no en el desarrollo de la aplicación en sí, nos saltaremos la capa de negocio o de servicios que debería tener este tipo de aplicaciones por capas.

2. POJO y DAO

El POJO representa la entidad que usaremos para la prueba, que como se ha mencionado antes, modela los datos de un superheroe cualquiera, con sus superpoderes, debilidades y demás características. Además de usarlo para la capa de persistencia, también usaremos la misma clase como DTO para transferir datos entre capas de negocio.

El DAO, por motivos de simplicidad, es una interfaz que se exitende del CrudRepository de Spring Data. De esta manera se implementan automaticamente las operaciones CRUD clásicas necesarias para nuestro ejemplo. Usaremos el nombre del superheroe como clave primaria de la entidad.

 3. Servicios web

Para implementar los servicios web en este caso usamos Spring MVC. Vamos a seguir en la medida de lo posible las recomendaciones y buenas prácticas en la implementación de servicios de este tipo. Estas recomendaciones afectan a varias características de los servicios, a saber:

  • URL del servicio
  • Método HTTP
  • Códigos HTTP de respuesta

A parte de esto, en nuestro caso, como vamos a invocar los servicios desde una página web, usaremos JSON para enviar y recibir los datos desde los mismos (se podría usar XML en su lugar).

Los servicios que vamos a implementar y sus características son los siguientes:

Inserta o modifica un superheroe

Inserta un nuevo superheroe, si éste no existe, o lo modifica con los datos enviados, si existe en función de su clave primaria (nombre).

Obtiene los datos de un superheroe concreto en función de su nombre

Borra un superheroe en función de su nombre

Muestra la lista completa de superheroes

 4. Tests de servicios y generación de documentación

El último paso es implementar los tests de integración de los servicios que además de testear la funcionalidad completa de los mismos, nos permitirá generar la documentación asociada según los criterios que indiquemos en dicha implementación.

Para testear los servicios web usamos MockMVC de Spring, que implementa un cliente HTTP que nos permite invocar dichos servicios y validar los códigos de respuesta HTTP recibidos así como el contenido de la respuesta.

Al mismo tiempo inicializamos la generación de la documentación usando la API de Spring REST Docs y especificamos los campos obligatorios de entrada de datos o los campos de los datos de retorno para los servicios relacionados.

 5. Asciidoctor

Definimos en un fichero de texto plano el contenido y el formato de la página HTML que se generará como índice de nuestra documentación. Para ello usamos la sintaxis de Asciidoctor. Además seguimos recomendaciones de buenas prácticas relacionadas con la redacción de este tipo de documentación, a saber:

  • Indicar en un apartado diferente los distintos tipos de códigos de respuesta HTTP y su significado
  • Indicar en un apartado diferente los tipos de métodos HTTP usados y su significado
  • Indicar el tipo de respuesta recibida cuando se generar un error
  • Para cada servicio web documentado, indicar un ejemplo de invocación de la URL usando curl, ejemplos de petición y respuesta HTTP y si fuera necesario, el significado de los campos de entrada y salida de los datos usados. Esta información es la que genera de forma automática Spring REST Docs en cualquier caso, salvo la descripción de los campos de entrada y/o salida, que tendríamos que especificar en cada test si queremos que se genere

La ruta al fichero se incluye en el plugin de Asciidoctor para Maven, en el pom.xml.

 6. Ejecución de tests y generación de documentación

Configuramos los plugin de Maven en el pom.xml para que se ejecute la generación de la documentación al generar un nuevo “release” de la aplicación, es decir, cuando se invoque el goal “package” de Maven. Previamente se ejecutarán los tests de forma automática. Si falla el test o la generación de la documentación para un servicio dado, se indicará en la salida por consola y no se generará ni el release ni la documentación de ninguno de los servicios.

Maven goals

Maven goals

7. Visualización de la documentación generada

La documentación se genera en la ruta indicada en el plugin de Maven (ver arriba). Por un lado se generan los “snippets” que es la documentación que corresponde a cada servicio, y por otro una página principal o índice HTML que enlaza a esso “snippets” según hayamos indicado en el fichero de texto plano que define la página y que se describe en el punto 5.

Índice generado

Índice generado

Descripción de los servicios web

Descripción de los servicios web

Spring Web Sockets con STOMP y SockJS (y Spring Boot)

Este nuevo post presenta un sencillo ejemplo del desarrollo de una aplicación web (lanzada e inicializada mediante Spring Boot) que hace uso de web sockets para establecer una comunicación bidireccional asíncrona entre el cliente (el navegador web) y el servidor (la aplicación ejecutada en el Tomcat embebido de Spring Boot).

Para ello usaremos:

- Spring Boot, para inicializar la aplicación, resolver las dependencias, ejecutarla en el Tomcat embebido, etc.

- Spring Web Sockets, para implementar la parte correspondiente a ellos.

- STOMP y SockJS para crear el cliente en JavaScript que se ejecutará desde una página web en el navegador y facilitar las comunicaciones via JSON.

El objetivo es desarrollar una aplicación web que:

- Conecte al servidor, estableciendo el canal de comunicación para recibir los mensajes desde el servidor.

- Envíe un mensaje al servidor y reciba una respuesta que mostrará por pantalla.

- Permanezca a la escucha de los mensajes que le lleguen desde el servidor y los imprima por pantalla.

- Finalice la conexión al servidor, cerrando el canal de comunicación establecido por los web sockets.

Los pasos a seguir serían los siguientes:

1. Inicialización de la aplicación con Spring Boot

Para conocer algo más sobre Spring Boot se puede consultar este otro post sobre el tema dentro del blog, o la documentación oficial. Basicamente lo que se pretende es usar Spring Boot para preparar una aplicación con todas las dependencias y configuraciones iniciales necesarias para desarrollar una aplicación web que soporte Spring Web Sockets. Usaremo Spring MVC y Spring Web Sockets para esto. Para ello creamos un proyecto Java en Eclipse, lo mavenizamos y añadimos las siguientes dependencias al pom.xml (podemos partir de la aplicación desarrollada en el post antes mencionado sobre Spring Boot):

 

2. Creamos los DTOs que usaremos para transferir la información entre el cliente y el servidor y viceversa

La aplicación que vamos a desarrollar es una sencilla web que facilita información meteorológica en tiempo real. Contaremos con un sencillo formulario web que permite introducir el nombre de una ciudad. Se envía el nombre de la ciudad al servidor y se recibe la información meteorológica sobre esa ciudad en ese momento. Además cualquier cliente que este escuchando en ese momento en el mismo canal, recibirá la misma información. También se puede recibir la información meteorológica en tiempo real si se escucha en el web socket y esta se envía de forma periódica desde el servidor.

Por lo tanto, tenemos dos tipos de mensajes. El que envía el cliente al servidor con el nombre de la ciudad, y el que envía el servidor al cliente con la información meteorológica. Esta información se enviará en JSON pero dentro del servidor se implementará como un par de DTOs o POJOs o Java beans, es decir, como un par de clases sencillas con sus atributos y metodos de acceso (get/set).

Como no tenemos capa de persistencia ni acceso a base de datos o similar, crearemos un mapa con datos en memoria (WeatherData.java) donde insertaremos unos cuantos DTOs con información meteorológica de tres lozalizaciones, con datos como el tipo de tiempo, la hora en formato ISO o el lugar. 3. Configuración de los Web Sockets La configuración de los web sockets se hace en este caso como casi todo en Spring Boot, mediante una clase java y usando anotaciones.

En este caso, indicamos con @Configuration que es una clase de configuración de Spring (lo que eran antes los antiguos XML). Ademas con @EnableWebSocketMessageBroker indicamos que vamos a configurar los web sockets. En el primer método establecemos el mecanismo (broker) que escribira en el canal de mensajes del servidor a los clientes y cuya URI (del canal) empezará por “/topic”. En este caso es un broker sencillo que solo mantiene sus mensajes en memoria (sin persistencia). También indicamos que los mensajes de los clientes al servidor irán dirigidos a una URL que empezará por “/app”. En el segundo método se establece “/weather” como la URI del web socket creado y se indica que se espera SockJS para establecer la comunicación desde el cliente.

4. El controlador (y los posibles servicios)

Esta parte comprende la implementación del web socket en sí. En este caso vamos a usar un @Controller de Spring MVC para desarrollar un servicio que recibe el mensaje desde el cliente y responde desde el servidor usando el web socket antes configurado.

También se puede desarrollar un servicio, bien a nivel de controlador web, o bien a nivel de servicio, que escriba directamente en el web socket desde el servidor. El cliente que este escuchando en el canal recibirá el mensaje igualmente.

 

Las anotaciones que aplican a los Web Sockets son @MessageMapping(“/weather”) y @SendTo(“/topic/weatherinfo”). La primera indica que la URL a la que hay que invocar para enviar el mensaje al web socket es “/weather”. Entonces el JSON enviado se parseará automaticamente al DTO que es el argumento del método, como en un servicio web o un método de Spring MVC. La segunda anotación indica que la respuesta del método se enviará automaticamente a “/topic/weatherinfo”. Esa sería la URL del canal de respuestas desde el servidor en el que tendría que escuchar el cliente para recibir las respuestas.

Tenemos por lo tanto un método (o servicio) que recibe mensajes de los cliente y los contesta usando el web socket (getWeatherInfo). Pero además tenemos un método (runWInfo) que escribe directamente en el web socket sin más (si se descomenta la anotacion de @Scheduled se ejecutará cada 2 segundos). Para ello hace uso del SimpMessagingTemplate, indica la URL del web socket a escribir y el mensaje a enviar (el DTO).

Resumiendo:

- Hemos configurado un web socket “llamado” “/weather” (ver punto 3).

- Los clientes escriben al web socket si envían un mensaje a “/app/weather” (ver punto 3).

- El servidor escribe al web socket si envía un mensaje a “/topic/weatherinfo” (ver punto 3 y 4).

- Se puede usar el web socket para recibir del cliente y enviar desde el servidor (como en un servicio web o peticion HTTP estandar) o solo para enviar desde el servidor.

5. El cliente de JavaScript

El cliente es una página HTML muy sencilla que hace uso de las siguientes funciones de JavaScript:

 

A su vez estas funciones hacen uso de las librerias stomp.js y sockjs.js. El objetivo es implementar un cliente en JavaScript que:

a. Establezca la conexión con el web socket del servidor.

b. Envie mensajes por el web socket.

c. Escuche todos los mensajes que le lleguen por el web socket y los muestre por pantalla.

Para ello primero ha de conectar. Al conectar, se suscribe al canal del web socket, es decir, ya lo puede usar para enviar y recibir. Despues puede enviar o simplemente permanecer a la escucha. En el momento en el que lea algo del canal, lo procesará. Esto es lo que hace los metodos antes expuestos. El método connect establece la conexión con el web socket “/weather” y suscribe el cliente al canal de escucha “/topic/weatherinfo” que es donde escribe el servidor. En el momento en que recibe algo, lo pasa al método showWeather para que lo procese como un JSON. El método sendPlace() escribe un JSON a la URL “/app/weather”, que como establecimos en la configuración, es la URL en la que el servidor recibirá los mensajes del cliente.

6. El ejemplo

Este sería el aspecto del ejemplo. En un primer momento aparece como desconectado:

Desconectado

Desconectado

Pulsando en el boton de “Connect” establecemos la conexión entre el cliente y el servidor a través del web socket.

Conectado

Conectado

Ahora podemos simplemente esperar a que el servidor nos envie algo, o podemos preguntar nosotros, usando el campo y el boton de “Send place”. Si ponemos “Madrid” y pulsamos…

Envio/Respuesta

Envio/Respuesta

Para apreciar la potencia de la comunicación via web sockets, si abrimos otro navegador y vamos a la misma página, recibiremos también el mismo mensaje del servidor aunque no hayamos preguntado. Si estamos conectados estamos escuchando al mismo canal de comunicación y recibiendo los mismos mensajes que el resto de los clientes. Un ejemplo práctico de esto podría ser un chat o cualquier aplicación en tiempo real.

Modo chat

Modo chat

Se puede descargar el proyecto para Eclipse a modo de ejemplo de este enlace. Y el código fuente desde Github. Más información sobre Spring Web Sockets desde la web oficial.

Iniciándose con Spring Boot (I)

Comenzamos una serie de posts sobre una tecnología de Spring muy interesante, llamada Spring Boot.

Spring Boot es una parte de Spring que nos permite crear diferentes tipos de aplicaciones de una manera rápida y sencilla. Sus características principales son que provee out-of-the-box una serie de elementos que nos permiten desarrollar diferentes tipos de aplicaciones de forma casi inmediata. Algunas de estas características son:

  • Servidores de aplicaciones embebidos (Tomcat, Jetty, Undertow)
  • POMs con dependencias y plug-ins para Maven
  • Uso extensivo de anotaciones que realizan funciones de configuración, inyección, etc.

Un ejemplo práctico del inicio de un desarrollo con Spring Boot puede ser el siguiente. A continuación crearemos un proyecto en Eclipse, lo configuraremos para usar Spring Boot y crearemos una primera aplicación web haciendo uso del Tomcat embebido que trae Spring Boot.

1. Creamos un proyecto Java en Eclipse

Creamos un proyecto Java estandar en Eclipse. En este caso estamos usando Eclipse Luna. Creamos un proyecto Java. Añadimos un directorio ‘java’ dentro de ‘src’ y establecemos la ruta ‘src/java’ como ruta de las fuentes dentro del classpath del proyecto. Esto no es necesario para Spring Boot, simplemente sirve para dar una estructura coherente al proyecto.

Proyecto en Eclipse

Proyecto en Eclipse

2. Mavenizamos el proyecto

Activamos las opciones de Maven para el proyecto para poder usar el pom a la hora de resolver dependencias, usar plug-ins, etc. Esto si es recomendable a la hora de usar Spring Boot ya que aunque podemos descargar los JAR necesarios, a la hora de usarlos y resolver otras dependencias, o generar diferentes distribuibles, será beneficioso disponer de Maven.

Al mavenizar el proyecto, se crea de forma automática el pom.xml del proyecto. Agregamos al POM lo siguiente:

Para que se añadan las dependencias necesarias para Spring Boot, plug-ins, etc, heredamos del POM de Spring Boot tal que asi:

 

En este caso, como vamos a desarrollar aplicaciones web, entre otras, añadimos la siguiente dependencia también:

 

Añadimos el siguiente plug-in para crear los JAR como ficheros ejecutables:

 

Por último, en caso de no disponer de una versión completa de Spring, agregamos la configuración de los siguientes repositorios en caso de tener que descargar las correspondientes dependencias:

 

El pom.xml final podria quedar tal que asi.

Ejecución en Maven

Ejecución en Maven

3. Implementamos la aplicación

Como ejemplo práctico de inicio, podemos codificar la siguiente clase:

 

Esta clase implementa un controlador web. Usa, ademas de Spring Boot, caracterísiticas de Spring MVC para ello. Las anotaciones presentes configuran la clase como controlador y establecen un mapeado entre el ‘/’ y una funcionalidad específica (devuelve un texto). La anotación @EnableAutoConfiguration configura la aplicación sin necesidad de otros ficheros de configuración XML, etc. Por último, se ejecuta el aplicativo usando la clase SpringApplication de Spring Boot.

4. Modificar las propiedades

El Tomcat embebido se lanza en el puerto 8080 por defecto. Como tenemos ese puerto ocupado, lo podemos cambiar usando diferentes mecanismos de propiedades del entorno de Spring Boot. Una de las formas de cambiar estas propiedades es usando el fichero application.properties. Spring Boot cargará automaticamente las propiedades que encuentre en el fichero application.properties si lo encuentra en una de las posibles localizaciones. Una de esas localizaciones es el directorio ‘config/’ dentro del directorio raíz del proyecto. Para más información acerca de la configuración de Spring Boot se puede consultar este enlace.

De esta manera, cambiamos el puerto de Tomcat al 9999:

 

Proyecto en Eclipse completo

Proyecto en Eclipse completo

5. Lanzar la aplicación

Finalmente solo nos queda compilar y lanzar la aplicación via Maven. Para ello podemos crear desde Eclipse un modo de ejecución via Maven con el plug-im m2 correspondiente. Lanzamos el goal ‘spring-boot:run’. Esto compila los cambios, ejecuta los posibles tests y lanza el aplicativo. En este caso, arranca el Tomcat embebido y ya tenemos la aplicación disponible en la siguiente URL:

http:\\localhost:9999

Ejecución desde Eclipse

Ejecución desde Eclipse

Spring Boot web app

Spring Boot web app