{"id":58,"date":"2023-05-01T17:56:37","date_gmt":"2023-05-01T22:56:37","guid":{"rendered":"https:\/\/georgethepenguin.dev\/?p=58"},"modified":"2023-05-01T17:56:38","modified_gmt":"2023-05-01T22:56:38","slug":"proof-of-concept-spring-boot-3-en-render","status":"publish","type":"post","link":"https:\/\/georgethepenguin.dev\/index.php\/2023\/05\/01\/proof-of-concept-spring-boot-3-en-render\/","title":{"rendered":"Proof of Concept: Spring Boot 3 en Render"},"content":{"rendered":"\n<p>Hola ping\u00fcinos! \ud83d\udc27Este es el primer post de mi blog \ud83e\udd73\ud83c\udf89.<\/p>\n\n\n\n<p>En d\u00edas anteriores, hice un Live en mi canal de <a href=\"https:\/\/www.twitch.tv\/george_the_penguin\" data-type=\"URL\" data-id=\"https:\/\/www.twitch.tv\/george_the_penguin\">Twitch<\/a> en respuesta a diferentes consultas realizadas por los equipos que se encuentran juiciosamente trabajando en la iniciativa de la comunidad <a rel=\"noreferrer noopener\" href=\"https:\/\/linktr.ee\/trycatch.tv\" data-type=\"URL\" data-id=\"https:\/\/linktr.ee\/trycatch.tv\" target=\"_blank\">Try-Catch<\/a> (<em>A quienes aprovecho la oportunidad de permitirme, de forma voluntaria y gratuita, ayudarles como consultor a los diferentes miembros que est\u00e1n aprendiendo construcci\u00f3n de software<\/em>) respecto a las siguientes situaciones que les empezaron a suceder:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u00danicamente pod\u00edan crear ambientes de ejecuci\u00f3n en Render con Java 11.<\/li>\n\n\n\n<li>Esto conllevaba a bajar de versi\u00f3n de Spring Boot a la versi\u00f3n 2, y tampoco poder utilizar la m\u00e1s reciente versi\u00f3n de Java LTS, Java 17.<\/li>\n\n\n\n<li>El ambiente de ejecuci\u00f3n en Render no soportaba correctamente la inclusi\u00f3n de librer\u00edas como Swagger.<\/li>\n<\/ul>\n\n\n\n<p>As\u00ed que con el fin de encontrar una propuesta de soluci\u00f3n a estas inquietudes y necesidades de los equipos, estuve trabajando en la siguiente prueba de concepto (<em>PoC, Proof of Concept, por sus siglas en ingl\u00e9s<\/em>) para desplegar una aplicaci\u00f3n backend en Spring Boot 3 que exponga una REST API simple y se pueda desplegar correctamente en el ecosistema Render.<\/p>\n\n\n\n<p>Pero primero, revisemos los siguientes conceptos:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Spring Boot<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Framework de c\u00f3digo abierto que facilita la creaci\u00f3n de aplicaciones empresariales en Java.<\/li>\n\n\n\n<li>Proporciona una plataforma integral que incluye caracter\u00edsticas como configuraci\u00f3n autom\u00e1tica, gesti\u00f3n de dependencias y una estructura de proyecto f\u00e1cil de usar.<\/li>\n\n\n\n<li>Simplifica significativamente el proceso de creaci\u00f3n de aplicaciones al reducir la cantidad de c\u00f3digo que necesita ser escrito.<\/li>\n\n\n\n<li>Permite a los desarrolladores enfocarse en la l\u00f3gica de negocio y no en la configuraci\u00f3n y detalles t\u00e9cnicos de bajo nivel.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Render<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Plataforma en la nube que permite a los desarrolladores implementar y escalar aplicaciones web y API de forma r\u00e1pida y f\u00e1cil.<\/li>\n\n\n\n<li>Ofrece caracter\u00edsticas \u00fatiles para los desarrolladores, como alojamiento de aplicaciones, bases de datos y m\u00e1s.<\/li>\n\n\n\n<li>Una de sus principales ventajas es su facilidad de uso y configuraci\u00f3n. Los desarrolladores pueden configurar y lanzar aplicaciones en cuesti\u00f3n de minutos.<\/li>\n<\/ul>\n\n\n\n<p>Ahora que hemos repasado los principales conceptos t\u00e9cnicos correspondiente a la prueba de concepto, determinemos cu\u00e1l es la alternativa de soluci\u00f3n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Docker<\/h2>\n\n\n\n<p>Tan simple como eso. Crear im\u00e1genes de nuestra aplicaci\u00f3n de las cuales podamos ejecutar contenedores en Render, definiendo las condiciones necesarias para la correcta ejecuci\u00f3n de nuestro sistema. Pero recordemos, qu\u00e9 es Docker:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Plataforma de contenedores de software que permite empaquetar y distribuir aplicaciones independientemente del sistema operativo.<\/li>\n\n\n\n<li>Los contenedores son una especie de paquete que incluye todo lo que una aplicaci\u00f3n necesita para ejecutarse, como c\u00f3digo, bibliotecas y dependencias.<\/li>\n\n\n\n<li>Los contenedores pueden ejecutarse en cualquier lugar donde Docker est\u00e9 instalado, lo que significa que se pueden crear aplicaciones en cualquier entorno y distribuirlas f\u00e1cilmente.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Requerimientos<\/h2>\n\n\n\n<p>Ahora que hemos definido cu\u00e1l es nuestra alternativa de soluci\u00f3n, delimitemos el alcance de nuestra prueba de concepto a trav\u00e9s de una lista de requerimientos funcionales y no funcionales. Vamos a crear un microservicio para administrar transacciones a trav\u00e9s de un REST API.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Funcionales<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Registrar Transacciones (Fecha, Valor y Descripci\u00f3n).<\/li>\n\n\n\n<li>Consultar (una o todas), editar y eliminar transacciones.<\/li>\n\n\n\n<li>Consultar el saldo actual, resultado de las transacciones.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">No Funcionales<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Utilizar una base de datos relacional.<\/li>\n\n\n\n<li>Desplegar en Render.<\/li>\n\n\n\n<li>Utilizar Spring Boot 3 y Java 17.<\/li>\n\n\n\n<li>Exponer en REST API.<\/li>\n\n\n\n<li>Generar documentaci\u00f3n OpenAPI.<\/li>\n\n\n\n<li>Realizar pruebas unitarias.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Modelo de Arquitectura<\/h2>\n\n\n\n<p>Para darnos una idea m\u00e1s general de la prueba de concepto, vamos a utilizar el modelo de arquitectura C4 para ir describiendo a diferentes niveles, c\u00f3mo vamos a construir nuestra aplicaci\u00f3n. Es verdad, que para ser una prueba de concepto tan sencilla, se podr\u00eda decir que no es necesario llegar a generar este modelado ni entrar a tanto nivel de detalle, pero quise realizar este ejercicio para ense\u00f1ar a los miembros de la comunidad que deben primero analizar la problem\u00e1tica y dise\u00f1ar la soluci\u00f3n antes de comenzar a programar c\u00f3digo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Contexto<\/h3>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized is-style-default\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-contexto.png\" alt=\"\" class=\"wp-image-64\" width=\"453\" height=\"497\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-contexto.png 604w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-contexto-274x300.png 274w\" sizes=\"auto, (max-width: 453px) 100vw, 453px\" \/><figcaption class=\"wp-element-caption\"><em>Modelo C4 de Contexto<\/em><\/figcaption><\/figure>\n\n\n\n<p>En este diagrama encontramos el contexto completo para nuestra aplicaci\u00f3n. Tenemos nuestro Sistema de Transacciones que funcionar\u00e1 para el registro y consulta de esta informaci\u00f3n, operaciones que ser\u00e1n realizadas por el Usuario de la misma. Nuestro contexto es bastante simple, y estamos asumiento que el Usuario realizar\u00e1 las peticiones al REST API directamente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Contenedores<\/h3>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-contenedores.png\" alt=\"\" class=\"wp-image-65\" width=\"519\" height=\"639\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-contenedores.png 692w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-contenedores-244x300.png 244w\" sizes=\"auto, (max-width: 519px) 100vw, 519px\" \/><figcaption class=\"wp-element-caption\"><em>Modelo C4 de Contenedores<\/em><\/figcaption><\/figure>\n\n\n\n<p>Para construir el sistema de nuestra prueba de concepto, utilizaremos dos contenedores:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Aplicaci\u00f3n API:<\/strong> Contenedor de Spring Boot 3 correspondiente al REST API de las transacciones.<\/li>\n\n\n\n<li><strong>Aplicaci\u00f3n DB:<\/strong> Contenedor de la base de datos relacional, en el motor PostgreSQL que almacenar\u00e1 la informaci\u00f3n de las transacciones.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Componentes<\/h3>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-componentes.png\" alt=\"\" class=\"wp-image-67\" width=\"534\" height=\"752\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-componentes.png 712w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-componentes-213x300.png 213w\" sizes=\"auto, (max-width: 534px) 100vw, 534px\" \/><figcaption class=\"wp-element-caption\"><em>Modelo C4 de Componentes<\/em><\/figcaption><\/figure>\n\n\n\n<p>Detallando los diferentes componentes que tendr\u00e1 el contenedor del microservicio de aplicaci\u00f3n REST API para las transacciones, encontramos los siguientes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Controlador REST de Transacciones:<\/strong> Corresponde a un Spring REST Controller que expondr\u00e1 los endpoints para interactuar con los clientes y realizar las operaciones de las transacciones.<\/li>\n\n\n\n<li><strong>Servicio de Transacciones:<\/strong> Es un Spring Service que contrendr\u00e1 toda la l\u00f3gica de negocio referente a las operaciones de las transacciones.<\/li>\n\n\n\n<li><strong>Repositorio de Transacciones:<\/strong> Un Spring Repository que gestionar\u00e1 todo el acceso a los registros de los transacciones y que realizar\u00e1 la comunicaci\u00f3n con la capa de persistencia, representada por la base de datos de la aplicaci\u00f3n.<\/li>\n\n\n\n<li><strong>Configuraci\u00f3n OpenAPI:<\/strong> Hace referencia a un Spring Configuration que manejar\u00e1 la configuraci\u00f3n necesaria que se genere la documentaci\u00f3n OpenAPI referente a los endpoints expuestos por el Controlador REST.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">C\u00f3digo<\/h3>\n\n\n\n<p>El modelo de c\u00f3digo 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.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Entidades de Base de Datos<\/h4>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"192\" height=\"162\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-spring-boot-render-db.png\" alt=\"\" class=\"wp-image-68\"\/><figcaption class=\"wp-element-caption\"><em>Modelo de Base de Datos<\/em><\/figcaption><\/figure>\n\n\n\n<p>Este podr\u00e1 ser el diagrama de base de datos m\u00e1s simple que hayamos visto \ud83d\ude05, pero dado los requerimientos que definimos para la prueba de concepto no necesitamos m\u00e1s. Cada una de las transacciones que ser\u00e1n almacenadas en la base de datos tendr\u00e1n los siguientes atributos:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>id:<\/strong> Identificador primario de cada transacci\u00f3n. Ser\u00e1 un UUID.<\/li>\n\n\n\n<li><strong>date_time:<\/strong> Fecha y hora de la transacci\u00f3n. El tipo de dato es un Timestamp.<\/li>\n\n\n\n<li><strong>amount:<\/strong> Monto de la transacci\u00f3n. Podr\u00e1 ser tanto positivo como negativo. El tipo de dato es un Double.<\/li>\n\n\n\n<li><strong>description:<\/strong> Descripci\u00f3n de la transacci\u00f3n. Ser\u00e1 un Varchar.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Clases<\/h4>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><a href=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc.png\"><img loading=\"lazy\" decoding=\"async\" width=\"2911\" height=\"1027\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc.png\" alt=\"\" class=\"wp-image-69\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc.png 2911w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-300x106.png 300w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-1024x361.png 1024w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-768x271.png 768w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-1536x542.png 1536w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/poc-2048x723.png 2048w\" sizes=\"auto, (max-width: 2911px) 100vw, 2911px\" \/><\/a><figcaption class=\"wp-element-caption\"><em>Modelo de Clases UML<\/em> <em>(Clic en la imagen para verla en mayor detalle)<\/em><\/figcaption><\/figure>\n\n\n\n<p>En este modelo de nuestra prueba de concepto encontraremos los siguientes paquetes y clases:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>model:<\/strong> Paquete que contiene el modelo de nuestra aplicaci\u00f3n.\n<ul class=\"wp-block-list\">\n<li><strong>entity:<\/strong> Paquete que contiene las entidades persistentes.\n<ul class=\"wp-block-list\">\n<li><strong>Transaction:<\/strong> Entidad referente a las transacciones.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>repository: <\/strong>Paquete que contiene los repositorios de persistencia.\n<ul class=\"wp-block-list\">\n<li><strong>TransactionRepository:<\/strong> Interfaz que hereda de <em>JpaRepository <\/em>del framework de Spring y que define las operaciones persistentes referentes a las transacciones.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>service:<\/strong> Paquete que contiene los servicios de l\u00f3gica de negocio.\n<ul class=\"wp-block-list\">\n<li><strong>TransactionService:<\/strong> Clase que posee todas las operaciones de la l\u00f3gica de negocio referente a las transacciones.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>exception:<\/strong> Paquete que contiene las excepciones propias de las operaciones de la l\u00f3gica de negocio.<\/li>\n\n\n\n<li><strong>TransactionException:<\/strong> Excepci\u00f3n referente a los errores generados por las operaciones de las transacciones. Hereda de la clase <em>Exception<\/em> de Java.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>controller:<\/strong> Paquete que contiene la gesti\u00f3n de los controladores de nuestro contenedor de aplicaci\u00f3n.\n<ul class=\"wp-block-list\">\n<li><strong>rest: <\/strong>Paquete que contiene los controladores REST.\n<ul class=\"wp-block-list\">\n<li><strong>TransactionRestController: <\/strong>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\u00f3n para la documentaci\u00f3n OpenAPI.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>advice:<\/strong> Paquete que contiene los manejadores de excepci\u00f3n.\n<ul class=\"wp-block-list\">\n<li><strong>RestResponseEntityExceptionHandler:<\/strong> Clase que hereda de <em>ResponseEntityExceptionHandler<\/em> del framework de Spring y que maneja las excepciones del tipo definido <em>TransactionException<\/em> que llegan a la capa de los controladores REST, para que se presenten con un formato definido.<\/li>\n\n\n\n<li><strong>ErrorResponse:<\/strong> Record que define el formato de respuesta a presentar cuando una <em>TransactionException<\/em> es generada y llega hasta la capa de los controladores REST.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>config:<\/strong> Paquete que contiene las clases de configuraci\u00f3n del contenedor de aplicaci\u00f3n.\n<ul class=\"wp-block-list\">\n<li><strong>openapi:<\/strong> Paquete que contiene las clases de configuraci\u00f3n para OpenAPI.\n<ul class=\"wp-block-list\">\n<li><strong>OpenApiConfig:<\/strong> Clase de configuraci\u00f3n para la gesti\u00f3n de la generaci\u00f3n de la documentaci\u00f3n OpenAPI.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Dependencias<\/h2>\n\n\n\n<p>Para poder construir nuestra aplicaci\u00f3n de transacciones de forma ordenada y eficiente, debemos utilizar una herramienta de gesti\u00f3n y construcci\u00f3n. Para nuestra prueba de concepto, utilizaremos Apache Maven. Las dependencias que necesitamos para construir nuestro proyecto se definen dentro del archivo <code>pom.xml<\/code> y son las siguientes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>org.springframework.boot<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>spring-boot-starter-data-jpa<\/strong>: Dependencia de Spring Boot que incluye el framework Spring Data JPA para trabajar con bases de datos relacionales de manera simplificada.<\/li>\n\n\n\n<li><strong>spring-boot-starter-web<\/strong>: Dependencia de Spring Boot que incluye las librer\u00edas necesarias para crear aplicaciones web, incluyendo un servidor web integrado.<\/li>\n\n\n\n<li><strong>spring-boot-starter-validation<\/strong>: Dependencia de Spring Boot que incluye el framework de validaci\u00f3n de datos Hibernate Validator.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>org.postgresql<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>postgresql<\/strong>: Dependencia de PostgreSQL que permite la conexi\u00f3n a una base de datos PostgreSQL utilizando JDBC.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>org.projectlombok<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>lombok<\/strong>: Dependencia que agiliza la creaci\u00f3n de clases Java, permitiendo crear getters y setters, constructores y otros m\u00e9todos de forma m\u00e1s sencilla.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>org.springdoc<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>springdoc-openapi-starter-webmvc-ui<\/strong>: Dependencia de Spring Boot que permite la generaci\u00f3n de documentaci\u00f3n OpenAPI (anteriormente conocida como Swagger) para APIs REST.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>org.apache.commons<\/strong>\n<ul class=\"wp-block-list\">\n<li><strong>commons-lang3<\/strong>: Librer\u00eda de Apache que proporciona utilidades para manipulaci\u00f3n de cadenas, operaciones con objetos, manejo de excepciones y otras operaciones comunes en programaci\u00f3n.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Implementaci\u00f3n<\/h2>\n\n\n\n<p>Listo! Ya teniendo claro nuestros requerimientos y el dise\u00f1o de soluci\u00f3n, realizamos la implementaci\u00f3n de nuestro c\u00f3digo de aplicaci\u00f3n.<\/p>\n\n\n\n<p>Nuestra prueba de concepto se llama <strong>render-spring-boot-rest-api-poc <\/strong>y se encuentra disponible en el siguiente repositorio de Github: <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/george-the-penguin\/render-spring-boot-rest-api-poc\" target=\"_blank\">https:\/\/github.com\/george-the-penguin\/render-spring-boot-rest-api-poc<\/a> . En el archivo <code>README<\/code> del repositorio se encuentran las instrucciones para la creaci\u00f3n, construcci\u00f3n y despliegue de la aplicaci\u00f3n (<em>En ingl\u00e9s<\/em>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Soluci\u00f3n Docker<\/h3>\n\n\n\n<p>Los siguientes son los aspectos m\u00e1s importantes para construir la soluci\u00f3n a partir de Docker para realizar un despliegue correcto en la plataforma Render:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Propiedades Aplicaci\u00f3n<\/h4>\n\n\n\n<p>El archivo <code>application.properties<\/code> debe contener las siguientes propiedades para que funcione la conexi\u00f3n a la base de datos:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>spring.datasource.driver-class-name:<\/strong> Indica la clase del controlador JDBC que se utilizar\u00e1 para conectarse a la base de datos. Obligatoria.<\/li>\n\n\n\n<li><strong>spring.jpa.hibernate.ddl-auto:<\/strong> Indica c\u00f3mo Hibernate debe manejar la creaci\u00f3n y actualizaci\u00f3n de tablas de la base de datos. Los valores comunes son &#8220;create&#8221;, &#8220;update&#8221; y &#8220;validate&#8221;. Obligatoria.<\/li>\n\n\n\n<li><strong>spring.jpa.show-sql:<\/strong> Indica si Hibernate debe imprimir las consultas SQL generadas en la consola. Opcional.<\/li>\n\n\n\n<li><strong>spring.jpa.properties.hibernate.format_sql:<\/strong> Indica si Hibernate debe formatear las consultas SQL generadas para que sean m\u00e1s legibles. Opcional.<\/li>\n\n\n\n<li><strong>spring.jpa.properties.hibernate.dialect:<\/strong> Indica el dialecto de la base de datos que se est\u00e1 utilizando. El dialecto se utiliza para generar las consultas SQL adecuadas para la base de datos. Obligatoria.<\/li>\n<\/ul>\n\n\n\n<p><code>spring.datasource.driver-class-name=org.postgresql.Driver<br>spring.jpa.hibernate.ddl-auto=update<br>spring.jpa.show-sql=true<br>spring.jpa.properties.hibernate.format_sql=true<br>spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect<\/code><\/p>\n\n\n\n<p>Es importante <strong>JAM\u00c1S COLOCAR LAS CREDENCIALES DE CONEXI\u00d3N A LA BASE DE DATOS EN EL ARCHIVO DE PROPIEDADES<\/strong>. \u26a0\ufe0f<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Dockerfile<\/h4>\n\n\n\n<p>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\u00ed como cualquier configuraci\u00f3n que deba aplicarse al contenedor.<\/p>\n\n\n\n<p>En este caso, creamos un Dockerfile con dos or\u00edgenes. En el primero usamos una imagen de Apache Maven compatible con Java 17 a la cual le pasamos el c\u00f3digo fuente de la aplicaci\u00f3n y el archivo <code>pom.xml<\/code> y ejecutamos los comandos de construcci\u00f3n del ejecutable. En el segundo origen, utilizamos una imagen que contenga Java 17, en la cual exponemos el puerto de aplicaci\u00f3n (8080) y copiamos el JAR (Archivo ejecutable) resultado del anterior origen; tambi\u00e9n copiamos un script bash que contiene las instrucciones de ejecuci\u00f3n, le damos permiso de ejecutarse dentro del contenedor y establecemos la instrucci\u00f3n de ejecuci\u00f3n de dicho script.<\/p>\n\n\n\n<p><code>FROM maven:3.9.1-eclipse-temurin-17-focal AS build<br>COPY src \/home\/app\/src<br>COPY pom.xml \/home\/app<br>RUN mvn -f \/home\/app\/pom.xml clean package<br><br>FROM openjdk:17-jdk-alpine<br>EXPOSE 8080<br>COPY --from=build \/home\/app\/target\/render-spring-boot-rest-api-poc*.jar \/usr\/local\/lib\/app.jar<br>COPY start.sh start.sh<br>RUN chmod +x start.sh<br>ENTRYPOINT [\".\/start.sh\"]<\/code><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Script Bash<\/h4>\n\n\n\n<p>El principal ingrediente de nuestra receta de soluci\u00f3n. Este script Bash nos permite ejecutar el JAR de aplicaci\u00f3n y pasar los valores de conexi\u00f3n de base de datos de forma oculta a trav\u00e9s de variables de entorno. En el script pasamos las siguientes propiedades de Spring:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>spring.datasource.url:<\/strong> Indica la URL de conexi\u00f3n a la base de datos. La URL incluye el protocolo de la base de datos (como &#8220;jdbc:postgresql&#8221;), la direcci\u00f3n IP o el nombre de host del servidor de la base de datos y el nombre de la base de datos.<\/li>\n\n\n\n<li><strong>spring.datasource.username:<\/strong> Indica el nombre de usuario que se utilizar\u00e1 para conectarse a la base de datos.<\/li>\n\n\n\n<li><strong>spring.datasource.password:<\/strong> Indica la contrase\u00f1a que se utilizar\u00e1 para conectarse a la base de datos.<\/li>\n<\/ul>\n\n\n\n<p><code>#!\/bin\/sh<br>java -jar \/usr\/local\/lib\/app.jar --spring.datasource.url=$DB_URL --spring.datasource.username=$DB_USER \\<br>--spring.datasource.password=$DB_PASSWD<\/code><\/p>\n\n\n\n<p>Las variables de entorno DB_URL, DB_USER y, DB_PASSWD deben ser establecidas en el ambiente del servicio web correspondiente a la aplicaci\u00f3n en Render.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuraci\u00f3n en Render<\/h2>\n\n\n\n<p>Dentro del dashboard de nuestra cuenta de Render, debemos realizar las siguientes operaciones:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configuraci\u00f3n de Base de Datos<\/h3>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-1-1024x632.png\" alt=\"\" class=\"wp-image-73\" width=\"768\" height=\"474\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-1-1024x632.png 1024w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-1-300x185.png 300w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-1-768x474.png 768w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-1.png 1117w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/><figcaption class=\"wp-element-caption\"><em>Configuraci\u00f3n de Conexi\u00f3n de la Base de Datos en Render<\/em><\/figcaption><\/figure>\n\n\n\n<p>En nuestra configuraci\u00f3n de base de datos PostgreSQL en Render, buscamos en la secci\u00f3n &#8220;Connections&#8221; la informaci\u00f3n del nombre de usuario (<em>Username<\/em>), contrase\u00f1a (<em>Password<\/em>) y URL.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configuraci\u00f3n de Servicio Web<\/h3>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-2-1024x426.png\" alt=\"\" class=\"wp-image-74\" width=\"1024\" height=\"426\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-2-1024x426.png 1024w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-2-300x125.png 300w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-2-768x319.png 768w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-2.png 1513w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"><em>Configuraci\u00f3n de Variables de Entorno del Servicio Web<\/em><\/figcaption><\/figure>\n\n\n\n<p>Luego, con la informaci\u00f3n obtenida de la configuraci\u00f3n de base de datos de Render, ingresamos a la configuraci\u00f3n del servicio web a exponer, correspondiente a nuestra aplicaci\u00f3n. Tras indicar cu\u00e1l es el repositorio Github de nuestra aplicaci\u00f3n, en la secci\u00f3n &#8220;Advanced&#8221; ingresamos las siguientes variables de ambiente que ser\u00e1n pasadas a nuestro contenedor. Esta informaci\u00f3n tras ser almacenada en la configuraci\u00f3n de Render, ser\u00e1n almacenadas como secretos y no podr\u00e1n volver a ser consultadas posteriormente, lo que hace este mecanismo mucho m\u00e1s seguro respecto al uso de nuestras credenciales.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PORT:<\/strong> Puerto expuesto en nuestra imagen de Docker. Internamente, Render har\u00e1 una redirecci\u00f3n del puerto HTTPS por defecto del servicio web expuesto resultante hacia este puerto interno.<\/li>\n\n\n\n<li><strong>DB_URL:<\/strong> URL JDBC de nuestra base de datos.<\/li>\n\n\n\n<li><strong>DB_USER:<\/strong> Usuario de nuestra base de datos.<\/li>\n\n\n\n<li><strong>DB_PASSWD:<\/strong> Contrase\u00f1a de nuestra base de datos.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Resultado<\/h2>\n\n\n\n<p>Finalmente, tendremos nuestra aplicaci\u00f3n desplegada y disponible en internet. \ud83c\udfc6<\/p>\n\n\n\n<p>En el caso de mi prueba de concepto desplegada, est\u00e1 en <a rel=\"noreferrer noopener\" href=\"https:\/\/render-spring-boot-rest-api-poc.onrender.com\/swagger-ui\/index.html\" target=\"_blank\">https:\/\/render-spring-boot-rest-api-poc.onrender.com\/swagger-ui\/index.html<\/a> . All\u00ed se puede consultar la documentaci\u00f3n OpenAPI del servicio REST.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"982\" height=\"591\" src=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-3.png\" alt=\"\" class=\"wp-image-75\" srcset=\"https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-3.png 982w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-3-300x181.png 300w, https:\/\/georgethepenguin.dev\/wp-content\/uploads\/2023\/05\/image-3-768x462.png 768w\" sizes=\"auto, (max-width: 982px) 100vw, 982px\" \/><figcaption class=\"wp-element-caption\">Documentaci\u00f3n OpenAPI del Servicio REST desplegado en Render.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusiones<\/h2>\n\n\n\n<p>Tras realizar este ejercicio de prueba de concepto, he llegado a las siguientes conclusiones:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Docker es la mejor forma de exportar nuestras aplicaciones a cualquier entorno.<\/li>\n\n\n\n<li>Spring Boot requiere recursos de hardware para una efectiva ejecuci\u00f3n. Render Free \u00fanicamente ofrece 512MB de RAM y 0.1 CPU (Tiempo de Start-Up aprox. 3 minutos).<\/li>\n\n\n\n<li>Podr\u00eda ser m\u00e1s efectivos frameworks m\u00e1s ligeros como Micronaut o Quarkus con generaci\u00f3n de im\u00e1genes nativas?<\/li>\n\n\n\n<li>Para la siguiente fase de la iniciativa TryCatch, es recomendable usar un entorno cloud m\u00e1s poderoso como AWS, por ejemplo.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Oportunidades<\/h2>\n\n\n\n<p>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\u00ed continuar mejorando nuestra prueba de concepto y aprendizaje:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Hay un error de dise\u00f1o en la aplicaci\u00f3n. Pueden detectar cu\u00e1l es?<\/li>\n\n\n\n<li>Cu\u00e1l t\u00e9cnica se puede utilizar para revisar que el c\u00f3digo fuente cumpla los est\u00e1ndares? Cu\u00e1les posibles errores se podr\u00edan encontrar?<\/li>\n\n\n\n<li>Revisar las pruebas unitarias con <strong>JUnit 5<\/strong> y el uso de <strong>Mockito<\/strong>.<\/li>\n\n\n\n<li>Aprender a usar Lombok y OpenAPI.<\/li>\n\n\n\n<li><strong>Importante<\/strong>: <strong>Aprender Docker!<\/strong><\/li>\n\n\n\n<li>Crear una interfaz gr\u00e1fica (Web o m\u00f3vil).<\/li>\n\n\n\n<li>Pregunten a los Team Leaders y Consultores de la iniciativa TryCatch. No desaprovechen esta oportunidad. Pidan revisi\u00f3n de c\u00f3digo a trav\u00e9s de los Pull Request.<\/li>\n<\/ul>\n\n\n\n<p>Quienes quieran responder a estas inquietudes, recibo sus respuestas en los comentarios de este post o en mis redes sociales. Tambi\u00e9n pueden crear forks del repositorio en Github y solicitar Pull Requests para mejorar nuestra prueba de concepto. Finalmente, pueden tambi\u00e9n proponer nuevas pruebas de concepto para que revisemos y trabajemos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Recursos de Aprendizaje<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Spring Boot<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/spring.io\/\" target=\"_blank\">https:\/\/spring.io\/<\/a><\/li>\n\n\n\n<li><strong>Render<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/render.com\/\" target=\"_blank\">https:\/\/render.com\/<\/a><\/li>\n\n\n\n<li><strong>Java<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/dev.java\/\" target=\"_blank\">https:\/\/dev.java\/<\/a><\/li>\n\n\n\n<li><strong>OpenAPI<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/www.openapis.org\/\" target=\"_blank\">https:\/\/www.openapis.org\/<\/a><\/li>\n\n\n\n<li><strong>Docker<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/www.docker.com\/\" target=\"_blank\">https:\/\/www.docker.com\/<\/a><\/li>\n\n\n\n<li><strong>Modelo C4<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/c4model.com\/\" target=\"_blank\">https:\/\/c4model.com\/<\/a><\/li>\n\n\n\n<li><strong>PostgreSQL<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/www.postgresql.org\/\" target=\"_blank\">https:\/\/www.postgresql.org\/<\/a> <\/li>\n\n\n\n<li><strong>Lombok<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/projectlombok.org\/\" target=\"_blank\">https:\/\/projectlombok.org\/<\/a><\/li>\n\n\n\n<li><strong>Apache Commons Lang<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/commons.apache.org\/proper\/commons-lang\/\" target=\"_blank\">https:\/\/commons.apache.org\/proper\/commons-lang\/<\/a><\/li>\n\n\n\n<li><strong>JUnit<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/junit.org\/junit5\/\" target=\"_blank\">https:\/\/junit.org\/junit5\/<\/a><\/li>\n\n\n\n<li><strong>Mockito<\/strong>: <a rel=\"noreferrer noopener\" href=\"https:\/\/site.mockito.org\/\" target=\"_blank\">https:\/\/site.mockito.org\/<\/a><\/li>\n\n\n\n<li><strong>Micronaut<\/strong>: <a href=\"https:\/\/micronaut.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/micronaut.io\/<\/a><\/li>\n\n\n\n<li><strong>Quarkus<\/strong>: <a href=\"https:\/\/quarkus.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/quarkus.io\/<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Hola ping\u00fcinos! \ud83d\udc27Este es el primer post de mi blog \ud83e\udd73\ud83c\udf89. En d\u00edas 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, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-58","post","type-post","status-publish","format-standard","hentry","category-sin-categoria"],"_links":{"self":[{"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/posts\/58","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/comments?post=58"}],"version-history":[{"count":9,"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/posts\/58\/revisions"}],"predecessor-version":[{"id":76,"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/posts\/58\/revisions\/76"}],"wp:attachment":[{"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/media?parent=58"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/categories?post=58"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/georgethepenguin.dev\/index.php\/wp-json\/wp\/v2\/tags?post=58"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}