Proof of Concept: Spring Boot 3 en Render

Hola ping眉inos! 馃惂Este es el primer post de mi blog 馃コ馃帀.

En d铆as anteriores, hice un Live en mi canal de Twitch en respuesta a diferentes consultas realizadas por los equipos que se encuentran juiciosamente trabajando en la iniciativa de la comunidad Try-Catch (A quienes aprovecho la oportunidad de permitirme, de forma voluntaria y gratuita, ayudarles como consultor a los diferentes miembros que est谩n aprendiendo construcci贸n de software) respecto a las siguientes situaciones que les empezaron a suceder:

  • 脷nicamente pod铆an crear ambientes de ejecuci贸n en Render con Java 11.
  • Esto conllevaba a bajar de versi贸n de Spring Boot a la versi贸n 2, y tampoco poder utilizar la m谩s reciente versi贸n de Java LTS, Java 17.
  • El ambiente de ejecuci贸n en Render no soportaba correctamente la inclusi贸n de librer铆as como Swagger.

As铆 que con el fin de encontrar una propuesta de soluci贸n a estas inquietudes y necesidades de los equipos, estuve trabajando en la siguiente prueba de concepto (PoC, Proof of Concept, por sus siglas en ingl茅s) para desplegar una aplicaci贸n backend en Spring Boot 3 que exponga una REST API simple y se pueda desplegar correctamente en el ecosistema Render.

Pero primero, revisemos los siguientes conceptos:

Spring Boot

  • Framework de c贸digo abierto que facilita la creaci贸n de aplicaciones empresariales en Java.
  • Proporciona una plataforma integral que incluye caracter铆sticas como configuraci贸n autom谩tica, gesti贸n de dependencias y una estructura de proyecto f谩cil de usar.
  • Simplifica significativamente el proceso de creaci贸n de aplicaciones al reducir la cantidad de c贸digo que necesita ser escrito.
  • Permite a los desarrolladores enfocarse en la l贸gica de negocio y no en la configuraci贸n y detalles t茅cnicos de bajo nivel.

Render

  • Plataforma en la nube que permite a los desarrolladores implementar y escalar aplicaciones web y API de forma r谩pida y f谩cil.
  • Ofrece caracter铆sticas 煤tiles para los desarrolladores, como alojamiento de aplicaciones, bases de datos y m谩s.
  • Una de sus principales ventajas es su facilidad de uso y configuraci贸n. Los desarrolladores pueden configurar y lanzar aplicaciones en cuesti贸n de minutos.

Ahora que hemos repasado los principales conceptos t茅cnicos correspondiente a la prueba de concepto, determinemos cu谩l es la alternativa de soluci贸n.

Docker

Tan simple como eso. Crear im谩genes de nuestra aplicaci贸n de las cuales podamos ejecutar contenedores en Render, definiendo las condiciones necesarias para la correcta ejecuci贸n de nuestro sistema. Pero recordemos, qu茅 es Docker:

  • Plataforma de contenedores de software que permite empaquetar y distribuir aplicaciones independientemente del sistema operativo.
  • Los contenedores son una especie de paquete que incluye todo lo que una aplicaci贸n necesita para ejecutarse, como c贸digo, bibliotecas y dependencias.
  • Los contenedores pueden ejecutarse en cualquier lugar donde Docker est茅 instalado, lo que significa que se pueden crear aplicaciones en cualquier entorno y distribuirlas f谩cilmente.

Requerimientos

Ahora que hemos definido cu谩l es nuestra alternativa de soluci贸n, delimitemos el alcance de nuestra prueba de concepto a trav茅s de una lista de requerimientos funcionales y no funcionales. Vamos a crear un microservicio para administrar transacciones a trav茅s de un REST API.

Funcionales

  • Registrar Transacciones (Fecha, Valor y Descripci贸n).
  • Consultar (una o todas), editar y eliminar transacciones.
  • Consultar el saldo actual, resultado de las transacciones.

No Funcionales

  • Utilizar una base de datos relacional.
  • Desplegar en Render.
  • Utilizar Spring Boot 3 y Java 17.
  • Exponer en REST API.
  • Generar documentaci贸n OpenAPI.
  • Realizar pruebas unitarias.

Modelo de Arquitectura

Para darnos una idea m谩s general de la prueba de concepto, vamos a utilizar el modelo de arquitectura C4 para ir describiendo a diferentes niveles, c贸mo vamos a construir nuestra aplicaci贸n. Es verdad, que para ser una prueba de concepto tan sencilla, se podr铆a decir que no es necesario llegar a generar este modelado ni entrar a tanto nivel de detalle, pero quise realizar este ejercicio para ense帽ar a los miembros de la comunidad que deben primero analizar la problem谩tica y dise帽ar la soluci贸n antes de comenzar a programar c贸digo.

Contexto

Modelo C4 de Contexto

En este diagrama encontramos el contexto completo para nuestra aplicaci贸n. Tenemos nuestro Sistema de Transacciones que funcionar谩 para el registro y consulta de esta informaci贸n, operaciones que ser谩n realizadas por el Usuario de la misma. Nuestro contexto es bastante simple, y estamos asumiento que el Usuario realizar谩 las peticiones al REST API directamente.

Contenedores

Modelo C4 de Contenedores

Para construir el sistema de nuestra prueba de concepto, utilizaremos dos contenedores:

  • Aplicaci贸n API: Contenedor de Spring Boot 3 correspondiente al REST API de las transacciones.
  • Aplicaci贸n DB: Contenedor de la base de datos relacional, en el motor PostgreSQL que almacenar谩 la informaci贸n de las transacciones.

Componentes

Modelo C4 de Componentes

Detallando los diferentes componentes que tendr谩 el contenedor del microservicio de aplicaci贸n REST API para las transacciones, encontramos los siguientes:

  • Controlador REST de Transacciones: Corresponde a un Spring REST Controller que expondr谩 los endpoints para interactuar con los clientes y realizar las operaciones de las transacciones.
  • Servicio de Transacciones: Es un Spring Service que contrendr谩 toda la l贸gica de negocio referente a las operaciones de las transacciones.
  • Repositorio de Transacciones: Un Spring Repository que gestionar谩 todo el acceso a los registros de los transacciones y que realizar谩 la comunicaci贸n con la capa de persistencia, representada por la base de datos de la aplicaci贸n.
  • Configuraci贸n OpenAPI: Hace referencia a un Spring Configuration que manejar谩 la configuraci贸n necesaria que se genere la documentaci贸n OpenAPI referente a los endpoints expuestos por el Controlador REST.

C贸digo

El modelo de c贸digo lo dividiremos en dos, dado que antes de iniciar con el modelo de clases, creo conveniente que revisemos el modelo de entidades de base de datos.

Entidades de Base de Datos

Modelo de Base de Datos

Este podr谩 ser el diagrama de base de datos m谩s simple que hayamos visto 馃槄, pero dado los requerimientos que definimos para la prueba de concepto no necesitamos m谩s. Cada una de las transacciones que ser谩n almacenadas en la base de datos tendr谩n los siguientes atributos:

  • id: Identificador primario de cada transacci贸n. Ser谩 un UUID.
  • date_time: Fecha y hora de la transacci贸n. El tipo de dato es un Timestamp.
  • amount: Monto de la transacci贸n. Podr谩 ser tanto positivo como negativo. El tipo de dato es un Double.
  • description: Descripci贸n de la transacci贸n. Ser谩 un Varchar.

Clases

Modelo de Clases UML (Clic en la imagen para verla en mayor detalle)

En este modelo de nuestra prueba de concepto encontraremos los siguientes paquetes y clases:

  • model: Paquete que contiene el modelo de nuestra aplicaci贸n.
    • entity: Paquete que contiene las entidades persistentes.
      • Transaction: Entidad referente a las transacciones.
    • repository: Paquete que contiene los repositorios de persistencia.
      • TransactionRepository: Interfaz que hereda de JpaRepository del framework de Spring y que define las operaciones persistentes referentes a las transacciones.
    • service: Paquete que contiene los servicios de l贸gica de negocio.
      • TransactionService: Clase que posee todas las operaciones de la l贸gica de negocio referente a las transacciones.
    • exception: Paquete que contiene las excepciones propias de las operaciones de la l贸gica de negocio.
    • TransactionException: Excepci贸n referente a los errores generados por las operaciones de las transacciones. Hereda de la clase Exception de Java.
  • controller: Paquete que contiene la gesti贸n de los controladores de nuestro contenedor de aplicaci贸n.
    • rest: Paquete que contiene los controladores REST.
      • TransactionRestController: Clase del controlador REST que expone los endpoints del API de las transacciones. Cada una de las funcionalidades referentes a los endpoints, tiene su descripci贸n para la documentaci贸n OpenAPI.
    • advice: Paquete que contiene los manejadores de excepci贸n.
      • RestResponseEntityExceptionHandler: Clase que hereda de ResponseEntityExceptionHandler del framework de Spring y que maneja las excepciones del tipo definido TransactionException que llegan a la capa de los controladores REST, para que se presenten con un formato definido.
      • ErrorResponse: Record que define el formato de respuesta a presentar cuando una TransactionException es generada y llega hasta la capa de los controladores REST.
  • config: Paquete que contiene las clases de configuraci贸n del contenedor de aplicaci贸n.
    • openapi: Paquete que contiene las clases de configuraci贸n para OpenAPI.
      • OpenApiConfig: Clase de configuraci贸n para la gesti贸n de la generaci贸n de la documentaci贸n OpenAPI.

Dependencias

Para poder construir nuestra aplicaci贸n de transacciones de forma ordenada y eficiente, debemos utilizar una herramienta de gesti贸n y construcci贸n. Para nuestra prueba de concepto, utilizaremos Apache Maven. Las dependencias que necesitamos para construir nuestro proyecto se definen dentro del archivo pom.xml y son las siguientes:

  • org.springframework.boot
    • spring-boot-starter-data-jpa: Dependencia de Spring Boot que incluye el framework Spring Data JPA para trabajar con bases de datos relacionales de manera simplificada.
    • spring-boot-starter-web: Dependencia de Spring Boot que incluye las librer铆as necesarias para crear aplicaciones web, incluyendo un servidor web integrado.
    • spring-boot-starter-validation: Dependencia de Spring Boot que incluye el framework de validaci贸n de datos Hibernate Validator.
  • org.postgresql
    • postgresql: Dependencia de PostgreSQL que permite la conexi贸n a una base de datos PostgreSQL utilizando JDBC.
  • org.projectlombok
    • lombok: Dependencia que agiliza la creaci贸n de clases Java, permitiendo crear getters y setters, constructores y otros m茅todos de forma m谩s sencilla.
  • org.springdoc
    • springdoc-openapi-starter-webmvc-ui: Dependencia de Spring Boot que permite la generaci贸n de documentaci贸n OpenAPI (anteriormente conocida como Swagger) para APIs REST.
  • org.apache.commons
    • commons-lang3: Librer铆a de Apache que proporciona utilidades para manipulaci贸n de cadenas, operaciones con objetos, manejo de excepciones y otras operaciones comunes en programaci贸n.

Implementaci贸n

Listo! Ya teniendo claro nuestros requerimientos y el dise帽o de soluci贸n, realizamos la implementaci贸n de nuestro c贸digo de aplicaci贸n.

Nuestra prueba de concepto se llama render-spring-boot-rest-api-poc y se encuentra disponible en el siguiente repositorio de Github: https://github.com/george-the-penguin/render-spring-boot-rest-api-poc . En el archivo README del repositorio se encuentran las instrucciones para la creaci贸n, construcci贸n y despliegue de la aplicaci贸n (En ingl茅s).

Soluci贸n Docker

Los siguientes son los aspectos m谩s importantes para construir la soluci贸n a partir de Docker para realizar un despliegue correcto en la plataforma Render:

Propiedades Aplicaci贸n

El archivo application.properties debe contener las siguientes propiedades para que funcione la conexi贸n a la base de datos:

  • spring.datasource.driver-class-name: Indica la clase del controlador JDBC que se utilizar谩 para conectarse a la base de datos. Obligatoria.
  • spring.jpa.hibernate.ddl-auto: Indica c贸mo Hibernate debe manejar la creaci贸n y actualizaci贸n de tablas de la base de datos. Los valores comunes son “create”, “update” y “validate”. Obligatoria.
  • spring.jpa.show-sql: Indica si Hibernate debe imprimir las consultas SQL generadas en la consola. Opcional.
  • spring.jpa.properties.hibernate.format_sql: Indica si Hibernate debe formatear las consultas SQL generadas para que sean m谩s legibles. Opcional.
  • spring.jpa.properties.hibernate.dialect: Indica el dialecto de la base de datos que se est谩 utilizando. El dialecto se utiliza para generar las consultas SQL adecuadas para la base de datos. Obligatoria.

spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Es importante JAM脕S COLOCAR LAS CREDENCIALES DE CONEXI脫N A LA BASE DE DATOS EN EL ARCHIVO DE PROPIEDADES. 鈿狅笍

Dockerfile

Un Dockerfile es un archivo de texto que contiene las instrucciones para construir una imagen de Docker. El Dockerfile especifica los componentes y dependencias necesarios para construir la imagen, as铆 como cualquier configuraci贸n que deba aplicarse al contenedor.

En este caso, creamos un Dockerfile con dos or铆genes. En el primero usamos una imagen de Apache Maven compatible con Java 17 a la cual le pasamos el c贸digo fuente de la aplicaci贸n y el archivo pom.xml y ejecutamos los comandos de construcci贸n del ejecutable. En el segundo origen, utilizamos una imagen que contenga Java 17, en la cual exponemos el puerto de aplicaci贸n (8080) y copiamos el JAR (Archivo ejecutable) resultado del anterior origen; tambi茅n copiamos un script bash que contiene las instrucciones de ejecuci贸n, le damos permiso de ejecutarse dentro del contenedor y establecemos la instrucci贸n de ejecuci贸n de dicho script.

FROM maven:3.9.1-eclipse-temurin-17-focal AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package

FROM openjdk:17-jdk-alpine
EXPOSE 8080
COPY --from=build /home/app/target/render-spring-boot-rest-api-poc*.jar /usr/local/lib/app.jar
COPY start.sh start.sh
RUN chmod +x start.sh
ENTRYPOINT ["./start.sh"]

Script Bash

El principal ingrediente de nuestra receta de soluci贸n. Este script Bash nos permite ejecutar el JAR de aplicaci贸n y pasar los valores de conexi贸n de base de datos de forma oculta a trav茅s de variables de entorno. En el script pasamos las siguientes propiedades de Spring:

  • spring.datasource.url: Indica la URL de conexi贸n a la base de datos. La URL incluye el protocolo de la base de datos (como “jdbc:postgresql”), la direcci贸n IP o el nombre de host del servidor de la base de datos y el nombre de la base de datos.
  • spring.datasource.username: Indica el nombre de usuario que se utilizar谩 para conectarse a la base de datos.
  • spring.datasource.password: Indica la contrase帽a que se utilizar谩 para conectarse a la base de datos.

#!/bin/sh
java -jar /usr/local/lib/app.jar --spring.datasource.url=$DB_URL --spring.datasource.username=$DB_USER \
--spring.datasource.password=$DB_PASSWD

Las variables de entorno DB_URL, DB_USER y, DB_PASSWD deben ser establecidas en el ambiente del servicio web correspondiente a la aplicaci贸n en Render.

Configuraci贸n en Render

Dentro del dashboard de nuestra cuenta de Render, debemos realizar las siguientes operaciones:

Configuraci贸n de Base de Datos

Configuraci贸n de Conexi贸n de la Base de Datos en Render

En nuestra configuraci贸n de base de datos PostgreSQL en Render, buscamos en la secci贸n “Connections” la informaci贸n del nombre de usuario (Username), contrase帽a (Password) y URL.

Configuraci贸n de Servicio Web

Configuraci贸n de Variables de Entorno del Servicio Web

Luego, con la informaci贸n obtenida de la configuraci贸n de base de datos de Render, ingresamos a la configuraci贸n del servicio web a exponer, correspondiente a nuestra aplicaci贸n. Tras indicar cu谩l es el repositorio Github de nuestra aplicaci贸n, en la secci贸n “Advanced” ingresamos las siguientes variables de ambiente que ser谩n pasadas a nuestro contenedor. Esta informaci贸n tras ser almacenada en la configuraci贸n de Render, ser谩n almacenadas como secretos y no podr谩n volver a ser consultadas posteriormente, lo que hace este mecanismo mucho m谩s seguro respecto al uso de nuestras credenciales.

  • PORT: Puerto expuesto en nuestra imagen de Docker. Internamente, Render har谩 una redirecci贸n del puerto HTTPS por defecto del servicio web expuesto resultante hacia este puerto interno.
  • DB_URL: URL JDBC de nuestra base de datos.
  • DB_USER: Usuario de nuestra base de datos.
  • DB_PASSWD: Contrase帽a de nuestra base de datos.

Resultado

Finalmente, tendremos nuestra aplicaci贸n desplegada y disponible en internet. 馃弳

En el caso de mi prueba de concepto desplegada, est谩 en https://render-spring-boot-rest-api-poc.onrender.com/swagger-ui/index.html . All铆 se puede consultar la documentaci贸n OpenAPI del servicio REST.

Documentaci贸n OpenAPI del Servicio REST desplegado en Render.

Conclusiones

Tras realizar este ejercicio de prueba de concepto, he llegado a las siguientes conclusiones:

  • Docker es la mejor forma de exportar nuestras aplicaciones a cualquier entorno.
  • Spring Boot requiere recursos de hardware para una efectiva ejecuci贸n. Render Free 煤nicamente ofrece 512MB de RAM y 0.1 CPU (Tiempo de Start-Up aprox. 3 minutos).
  • Podr铆a ser m谩s efectivos frameworks m谩s ligeros como Micronaut o Quarkus con generaci贸n de im谩genes nativas?
  • Para la siguiente fase de la iniciativa TryCatch, es recomendable usar un entorno cloud m谩s poderoso como AWS, por ejemplo.

Oportunidades

Y las anteriores conclusiones y reflexiones del ejercicio realizado nos abre las siguientes oportunidades de estudio para los miembros de la comunidad Try-Catch, para as铆 continuar mejorando nuestra prueba de concepto y aprendizaje:

  • Hay un error de dise帽o en la aplicaci贸n. Pueden detectar cu谩l es?
  • Cu谩l t茅cnica se puede utilizar para revisar que el c贸digo fuente cumpla los est谩ndares? Cu谩les posibles errores se podr铆an encontrar?
  • Revisar las pruebas unitarias con JUnit 5 y el uso de Mockito.
  • Aprender a usar Lombok y OpenAPI.
  • Importante: Aprender Docker!
  • Crear una interfaz gr谩fica (Web o m贸vil).
  • Pregunten a los Team Leaders y Consultores de la iniciativa TryCatch. No desaprovechen esta oportunidad. Pidan revisi贸n de c贸digo a trav茅s de los Pull Request.

Quienes quieran responder a estas inquietudes, recibo sus respuestas en los comentarios de este post o en mis redes sociales. Tambi茅n pueden crear forks del repositorio en Github y solicitar Pull Requests para mejorar nuestra prueba de concepto. Finalmente, pueden tambi茅n proponer nuevas pruebas de concepto para que revisemos y trabajemos.

Recursos de Aprendizaje

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top