Como crear un microservicio o servicio web REST con Spring Boot (Parte 1)

Hace unos días durante una consultoría en implementación de arquitectura de microservicios, realizamos un pequeño taller práctico en el que un equipo de desarrollo que suele trabajar con JavaEE, aprendió a construir un servicio web sencillo pero completo con Spring Boot.

Esta experiencia me pareció valiosa para para ayudar a que los desarrolladores que se inician en este framework no se pierdan en el vasto océano que es Spring y guiarlos en los temas básicos que deben aprender para poder atender una de las peticiones más comunes que recibimos todos como desarrolladores: construir un servicio web REST con una base de datos relacional.

He dividido este post en tres partes: en la primera construiremos un servicio web básico, con lo mínimo que se necesita para ser operativo. En la segunda parte incluiremos el acceso a la base de datos. En la tercera lo enriqueceremos con algunas de las características que hacen tan poderoso a Spring Framework. En todos los posts veremos algunos tips y mejores prácticas genéricas para que construyas software SinBugs.

Para los más impacientes, el código del tutorial completo lo pueden encontrar en nuestro repositorio en GitHub

Diseño del microservicio

Para utilizar alguna temática, crearemos un servicio web para la administración de información de contactos, como nombre, teléfono, email, etc.

Una buena práctica de diseño de software (debería ser obligatoria!) es la aplicación del principio de separación de responsabilidades (separation of concerns) que consiste en asegurarse que cada clase, componente, etc. tenga una responsabilidad bien definida, es decir, que sus funcionalidades o métodos no hagan más de un tipo de actividad, por ejemplo, dibujar la página web y guardar datos en una base datos.

Un ejemplo de la falta de separación de responsabilidades es cuando en un script PHP se «pintan» tags HTML y unas (miles!) líneas más abajo, se establece la conexión a la base de datos para consultar o guardar información. Esto lleva a producir software difícil de mantener, actualizar y corregir, entre muchos otros problemas muy graves.

La separación de responsabilidades se aplica en diferentes formas y niveles. En este caso la usaremos para separar tres responsabilidades bien definidas:

  1. Interactuar con el cliente del servicio (capa interfaz o presentación). Aquí agrupamos las clases y métodos que conforman el API del servicio web.
  2. Ejecutar procesamientos y aplicar reglas de negocio. Estas son clases que tienen la «sabiduría» o conocimiento sobre la lógica de lo que hace el servicio web. Algunos llaman a estas clases, «servicios«
  3. Acceso a datos. Son las clases que se encargan de almacenar y extraer la información de un repositorio. Algunos las llaman Repository o Data Access Object (DAO)

Adicionalmente tenemos un tipo de objeto que transporta la información entre estas capas de nuestra aplicación, para reducir el acoplamiento. Son los llamados Data Transport Object (DTO) o Value Object (VO) que se implementan como objetos planos de java (Plain Old Java Object o POJO), es decir, simples contenedores de datos, sin métodos o comportamiento.

Un tipo de objeto muy parecido a los DTO son las entidades (entity) que representan tablas o registros en la base de datos. La mejor práctica es extraer un entity de la base de datos y asignar algunos de sus valores a un DTO equivalente para retornarlo a la capa superior en lugar de retornar el entity. Es una práctica discutible porque por ser tan parecidas las entities con los DTO, el código parecerá duplicado; en su favor argumentamos que evita que el cliente reciba información muy detallada de la base de datos o campos que no queremos que reciba (ej: hash del password), reduciendo así el acoplamiento y mejorando la abstracción.

Creando el proyecto

Usaremos un proyecto Maven que es genérico y puede usarse en eclipse, Netbeans, IntelliJ IDEA o cualquier otro IDE Java, incluso con editores de texto de línea de comandos. Tenemos por lo menos tres formas de crear el proyecto:

  1. Por comandos de maven: simple pero entonces este post sería sobre Maven y no sobre Spring Boot…
  2. Usando el sitio web de Spring Boot Initializr, en el cual podremos seleccionar los parámetros del proyecto, las librerías a incluir y descargar un zip que contiene nuestro proyecto base, el cual debemos importar en nuestro IDE favorito
  3. Utilizando Spring Tool Suite (STS) que es un conjunto de plugins para Eclipse, especialmente diseñados para hacernos muy productivos al desarrollar una aplicación de Spring. Usaremos esta opción que básicamente es una fachada pues STS se conecta a Spring Boot Initializr para hacer lo mismo que haríamos visitando el sitio web, sólo que importa automáticamente el proyecto en nuestro IDE.

Para crear el proyecto, en STS selecciona el menú «File/New/Spring Starter Project…» y en la ventana del asistente, ingresa los datos de tu proyecto, por ejemplo en nuestro caso, se verían así:

En la siguiente ventana selecciona las librerías Web (clases para páginas y servicios web), JPA (Hibernate y otras librerías para acceder a la base de datos) y H2 (base de datos en memoria para facilitar el desarrollo y pruebas). Presiona el botón «Finish» para completar la generación del proyecto:

Unos pocos segundos o minutos después, tendrás el proyecto listo en tu IDE. Prúebalo ejecutándolo como una aplicación Java normal: selecciona el proyecto, click derecho y pulsa el menú «Run as…/Java Application«. También funciona con el menú «Run as…/Spring Boot Application«. Con este último, el log de la consola se verá en colores facilitando su lectura. Si todo va bien, el proyecto debería iniciar sin errores en el log.

Agregando la capa DTO

Vamos a crear una clase simple (POJO) para representar a un contacto. Una buena práctica es agrupar las clases en paquetes según su responsabilidad: dao, dto, service, api, etc., así que crea estos paquetes (o como los quieras llamar), así:

En el paquete dto o entity o como hayas llamado al que contendrá tus objetos de datos, crea la clase Contact y añade campos como un id único, nombre, apellido, teléfono, email y otros que consideres:

package com.sinbugs.contacts.dto;

public class Contact {
 Long id;
 String firstName;
 String lastName;
 String phoneNumber;
 String email;
}

TIP: Después de agregar los campos básicos, utiliza los menús (con click derecho) «Source/Generate Getters and Setters…», «Source/Generate Constructor using Fields…» y «Source/Generate toString()…» para generar el resto del código requerido por el POJO o DTO. toString() te será muy útil en la depuración y registro en el log y para mejor rendimiento, utiliza StringBuffer o StringBuilder.

Creando el API

Para crear la interfaz REST del servicio web, crea la clase ContacsApi en el paquete Api y agrega un método básico para consultar un contacto por un ID, así:

package com.sinbugs.contacts.api;

import com.sinbugs.contacts.dto.Contact;

public class ContactsApi {
	
	public Contact getById(){
		return new Contact(1L, "John", "Doe", "+57 311 222 3344", "[email protected]");
	}
}

Por ahora el contacto estará «quemado» (hard-coded) en el API pero más adelante cambiaremos esto para que lo consulte de la base de datos.

Ya tenemos nuestra clase Api pero aún le falta para que sea un servicio web: para que Spring reconozca una clase como servicio web y la trate como tal, debemos anotar la clase con @RestController. También debemos anotar cada método público que deseemos exponer a los clientes con la anotación @RequestMapping, así:

@RestController
public class ContactsApi {
	
	@RequestMapping(value="/product", method=RequestMethod.GET)
	public Contact getById(){
		return new Contact(1L, "John", "Doe", "+57 311 222 3344", "[email protected]");
	}
}

La anotación @RequestMapping recibe parámetros que nos ayudan a cambiar la definición del método hacia el exterior: los content type que recibe o entrega, los headers que requiere, etc. En este caso los básicos son value, para indicar la url en la cual «escuchará» este método y method que indica el método HTTP que iniciará la ejecución de esta operación. Por defecto es GET, así que en este caso podríamos no dejar sólo el parámetro value y el servicio funcionaría igual.

Ahora ejecuta la aplicación y dirige el navegador hacia http://localhost:8080/product (si no has cambiado las configuraciones por defecto) y verás algo similar a esto, según tu navegador:

Felicitaciones! ya tienes tu microservicio básico y operativo. En la segunda parte de este post aprenderás a consultar y guardar contactos en la base de datos y usar parámetros para invocar al servicio web.

Recuerda que puedes encontrar el código del tutorial completo en nuestro repositorio en GitHub

Revisa las otras partes de este post:

« »