Saltar al contenido

Autor: Walberth

Crear web con Thymeleaf y Spring boot

Esta semana, me consultaron por las alternativas que se tienen en Spring para implementar el patrón MVC del lado del frontend, de las múltiples formas que se tienen, la que más me llama la atención es thymeleaf dado que es lo más cerca a código html puro. En este post quiero explicar como podemos crear un proyecto con spring, en el que useamos thymeleaft para el desarrollo de las vistas, añadiendo contenido estático (js, css) a nuestra web y consumiendo una base de datos como postgres usando jdbc.

Como indico en el parrafo anterior, en este post usaremos las siguientes herramientas:

  • Spring initializr
  • Spring JDBC
  • Spring Web Started
  • Thymeleaf
  • Lombok
  • PostgreSQL

Nuestro proyecto en cuestión, consiste en la realización de una página web donde podemos visualizar los logs que se generen en una aplicativo, siendo estos de los distintos tipos que existen. El proyecto en cuestión es uno personal que tengo en mente y pienso desarrollarlo en conjunto con una serie de post, se me hace interesante por que me permitirá agrupar el logging de diversar aplicaciones. Soy consciente que actualmente existen herramientas que brindan esta información con dashboards muy completos entre otras ventajas. Pero, no me negarán que existe una mistica especial en crear algo uno mismo desde cero. Además quiero que en esta aplicación también se pueda visualizar las consultas que se efectuan al motor de postgres, siendo este un simil al SQL Profiler que tenemos en SQL Server, he buscado exhaustivamente alguna alternativa que me permita conseguir esto y no la he encontrado, motivo por el cual me plantee generar una por mi mismo, siendo consciente que muy probablemente no tenga todas las características inicialmente que podemos encontrar en la herramientas de microsoft. Volviendo al post que nos reclama, iniciaremos creando un proyecto de la siguiente manera:

Creación del proyecto con Intellij IDEA
Selección de las dependencias

Con el proyecto creado, replicamos la estructura ya antes mencionada para el repository, service y controller. Me dedicaré a explicar como se configuran los archivos estáticos y la demás configuración correspondiente a la integración con thymeleaft.

Debemos copiar los archivos que vamos a usar en la siguiente ruta de nuestro proyecto:

Ubicación de los archivos estáticos

Para nuestros archivos html, creamos una carpeta shared en la que pondremos archivos como el header o el footer de nuestra aplicación, esto será usado como fragment en nuestras demás vistas. Para este primer post, sólo creare el “index” de nuestra aplicación en donde desarrollare una solicitud para llenar un combo con información de base de datos y la realización de un post.

Ubicación de los HTML del proyecto

En el header, importaremos las dependencias css y js. Además de realizar ciertas configuraciones para poder usarlo como fragment en nuestras demás vistas.

Importar estilos con thymeleaft:

<link rel="stylesheet" 
          th:href="@{/lib/plugins/daterangepicker/daterangepicker.css}">

Importar javascript con thymeleaft:

<script th:src="@{/lib/plugins/jquery/jquery.min.js}"></script>

Configurar una sección HTML en el header para ser llamada como fragment:

Configuración como fragment

Como se puede ver, se indica que es un fragment y se le asigna un nombre por el cual será llamada, el html en cuestión es un loader a ser usado en las demás páginas html cuando carguen.

En el controlador, cuando trabajemos con MVC, es necesario usar la notación “@Controller” en lugar de “RestController” que usabamos cuando trabajamos con APIS. el primer controller a crear es el index y posee la siguiente estructura.

Creación del controller que dirije al index

Como se ve, es un controller del tipo string, y debe retornar el nombre del html, para nuestro caso “logger”. Es necesario que nuestro index tenga el tipo de entrada “Model” que es una clase propia del framework que nos permite indicarle a la vista los atributos con los cuales trabajará. Como podemos ver, estoy declarando un atributo con el nombre “search” que es del tipo “SearchLog” que es una entidad que posee los siguientes campos:

Entidad SearchLog

Los campos que estén dentro de nuestro formulario html, deben tener los mismos valores definidos para nuestra entidad “SearchLog”. Además, se añaden otros dos atributos, que contienen las listas de nombres de las máquinas en las cuales se generaron los logs y los nombres de las aplicación de las cuales se tiene log registrados. En la vista “logger”, se tiene la siguiente configuración:

Llamada al fragment:

Llamada al fragment head desde el logger

Como se puede observar, hago un insert del fragment, indicando la ubicación del archivo que lo contiene y el nombre que le indicamos.

Configuración del form:

Configuración del form

En este “form” es importante notas que se está indicando la acción a la cual debe dirigir “/search”, el objecto que contiene que lleva el nombre “search” y si ven el post lineas arriba es el nombre que le indicamos en el model e indicar que es del tipo post. Por otro lado los campos contenidos en el form, poseen los nombres exactos que se definieron en la entidad y finalmente, para la lista que se devuelve, se itera sobre esta y se esta indicando en el valor y el texto a desplegar el mismo valor que es el nombre.

En el controlador tenemos que definir un método post con nombre “search”, quedando de la siguiente manera:

Controlador “search”

Es necesario definir como entrada de nuestro controlador un “@ModelAttribute” que debe ser del mismo tipo que definimos en nuesto model y del que posee nuestro form, para que pueda ser mapeado correctamente. Finalmente, llenamos los datos en nuestra entidad.

Llenado de datos en nuestro formulario

Presionamos el botón “search” y deberíamos llegar a nuestro método post con variable de entrada “SearchLog” y los campos que hemos ingresado.

Llegada de la información al controlador correctamente

Como podemos ver, es relativamente sencillo configurar y empezar a trabajar con thymeleaft, en otros post explicare la integración que podemos realizar con spring secutiry y sessions usando esta herramienta. Espero que les haya servido, como en los otros post dejo el link al repositorio de github del proyecto y el video.

REPO: GITHUB

Saludos.

Deja un comentario

Grabar log de errores en db y archivo con Spring Boot

Llevo ya algunas semanas revisando cursos sobre Spring, como he mencionado en publicaciones anteriores, el trabajo me lleva a desarrollar más en tecnologías de Microsoft. Sin embargo, conforme voy aprendido más de spring, me interesa más por lo pontente que es y el beneficio que brinda al evitar la repetición de código que no le suma nada a la lógica de negocio o ”  boilerplate code “.

El post de hoy, lo centrare en el grabado de logging cuando tenemos una aplicación hecha con spring boot, como saben el log es fundamental dado que un buen log nos permite resolver los problemas de nuestro aplicativo sin mucha demora, en un post posterior explicare lineamientos para generar un buen log y buenas practicas en el mismo. Sin embargo me interesa hacer un post de esto acá porque he tenido que revisar mucho la documentación para poder configurar el log como lo necesitaba en spring y no pude encontrar ningún lugar donde expliquen detenidamente como poder realizar esto.

El log que grabaremos se realizará en base de datos (postgres) y un archivo de texto (.txt), se pueden tener multiples tipos (niveles) de log, que nos permiten medir la usabilidad de los features, los errores y las caidas fatales del sistema, para la demo me enfocare en los errores y explicare como en spring podemos capturar todos los errores que se generen, grabarlos en base de datos y el archivo de texto y al usuario mostrarle un mensaje de texto genérico y un código vinculado a nuestro registro de error.

APLICATIVO

Estoy usando Intellij IDEA como IDE para el desarrollo de esta demo, y la aplicación se divide en repository, service y controller. Considerando que el repository y service tenemos una implementación para las interfaces que definimos. Además, en repository tenemos una capa para hacer el mapping a entidades de lo recibido por la base de datos.

Project files de Spring boot

Para grabar los logs, usar log4j2 que es una librería de amplia trayectoria y bien documentada, para configurarla en la sección de resources de nuestra aplicación es necesario crear un archivo de configuración, este puede ser un xml, json o un properties. En mi caso cree un “log4j2.properties” .

Archivo de configuración del log

En el properties de spring es necesario indicarle que tenemos un archivo de configuración de log con las siguientes sentencias:

Configuración en el application.properties para el log

En el log4j2.properties que hemos creado es necesario indicar la siguiente configuración.

Configuración del log en log4j2.properties

En esta estamos indicando el indicando al configuración de la base de datos, es necesario indicar cada columna de la tabla que hemos destinado para los logs en base de datos con los valores que se van a considerar para cada columna. También está la configuración para el archvo de texto, finalmente se indica que ambos appender deben ser utilizados y el nivel mínimo del log.

También es posible indicar en el log variables configuradas por nosotros, para mi caso es necesario saber el endpoint que se está consumiendo, el nombre del método del endpoint, el nombre del método donde el error ocurrio, un guid para vincular el error a un identificador único entre otros valores. Esto podemos conseguirlo seteando variables como propiedades del sistema y luego leyendo en nuestro log4j2.propierties.

Seteo de variables como propiedades del sistema
Obtenemos la propiedad del sistema en log4j2.properties

Una explicación didáctica de esta configuración así como algunas cosas que no pongo en el post para no hacerlo muy extenso lo encuentran en el video. Quedan muchos puntos por detallar más que desarrolloraré en otros posts, espero que les haya sido de utilidad y como siempre dejo los links al repositorio para que revisen ustedes el código.

REPO: GITHUB

Saludos.

1 comentario

Llamar un Mock Object dos veces con distintos resultados

Recientemente en el trabajo nos enfrentamos a un escenario cuando estabamos creando los test unitarios de un proyecto. Usando Moq como librería para el mocking queriamos que al llamar a un mismo método en el repositorio obtengamos distintos resultados por cada llamada. Ya en un post anterior he tratado un tema similiar a este con test unitarios, pero en los escenarios más simples es sólo necesario realizar un llamado obtener el resultado desarrollar cierta lógica de negocio con este resultado y evaluar los aserciones en el test.

Me parecio interesante desarrollar un poco más este tema y por eso hago este post, en el les explicaré un poco sobre las distintas opciones que tenemos para poder obtener distintos resultados al llamar a mock object con Moq, siendo una de estas opciones “SetupSequence” que es un overload al método setup que existe en esta librería, lo que podría generar un problema es que este overload es relativamente reciente, dado que recién se a incorporado como parte de la librería el 20 de junio del 2019. Y la otra opción es el uso de una estructura de datos como las queue o colas.

Para el desarrollo del post, me valdré del mismo proyecto que trabajamos en el post pasado, simplemente he añadido nuevos método en la capa de aplicación y en el repositorio y nuevos test unitarios.

APLICACION

Nuevo método en la capa de aplicación

Este método, como ven simplemente llama dos veces al mismo método del repositorio, con distintos parametros de entrada y retorna la concatenación de ambos resultados.

REPOSITORIO

Nuevo método en la capa de repositorio

Como ven, en el repositorio también se ha creado un nuevo método acá se está intentando simular que se llega a una base de datos, pero por fines prácticos se está devolviendo el nombre completo para todas las llamadas. Veamos los nuevos test unitarios desarrollados.

TEST

Uso de SetupSequence

Como pueden ver, con el uso de “SetupSequence” es posible realizar más de “Returns” los cuales, se van devolviendo conforme se van llamando, de manera tal que en el primer llamado desde la capa de aplicación, se devuelve “walberth”, y en el segundo “angela” y finalmente, se retorna la concatenación.

Uso de queue (Colas)

La otra forma de conseguir el mismo resultado, es valiendonos del uso de colas, como saben esta estructura de datos es del tipo FIFO (first in, first out), de modo que cada ves que llamemos a nuetro moq, y su objeto de retorno es del tipo Queue va a devolver los objetos de este modo.

Espero que les sirva de ayuda como hemos podido resolver este escenario, tal ves con un caso tan común, pero cuando ocurre puede que nos tome un par de horas ver la forma de darle solución. Como siempre, dejo el video del desarrollo de esta solución y los links a github.

REPO: GITHUB

Saludos.

1 comentario

Unit Test y Mocking en NetCore

Cuando empezamos a desarrollar, sea el lenguaje que nos adopte incialmente no solemos tener en consideración los test unitarios y mucho menos el mocking. Si nos dedicamos a este mundo del desarrollo, tarde o temprano vamos a tener que llegar a saber para que sirven y como implementarlos, y de esto de lo que busco escribir un poco hoy.

TEST UNITARIOS

Los test unitarios son secciones de código de escribimos, cuyo objetivo es probar el funcionamiento y funcionalidad de otros métodos que hayamos desarrollado. Es importante tener claro el concepto de atomicidad al querer realizar un test unitarios, dado que el método a probar que se ha desarrollado debemos intentar que posea una única responsabilidad, de manera tal que nuestros test unitarios puedan ser atómico.

MOCKING

Cuando nos referimos a mocking, debemos tener claro que se tiene que llevar a cabo con una prueba unitaria, y lo que nos permite es abstraer el método que queremos probar de otras dependencías que no se están probando. De tal manera, podemos aislar nuestro test unitario y conseguir que sean realmente atómicos.

En el ejemplo que llevaremos a cabo, explicare como implementar un test unitario en Net Core 2.2, usando una librería para poder aplicar mocking en nuestro test. Para conseguir esto, usaremos XUnit para el test unitaio y Moq para el mocking. Es importante recalcar que existen otras opciones y que los conceptos que se aplicarán en la demo, puedes tranquilamente extrapolarse a alguna otra librería que se quiera usar.

Para empezara crear nuestro proyecto, se tiene la siguiente estructura en un proyecto demo:

Distribución del proyecto demo
Nuget utilizados en el test unitario

La arquitectura no es lo importante en esta demo, pero basicamente tenemos una capa de presentación (aplicación consola), una capa de aplicación y una de repositorio, en esta última se debe tener acceso a la base de datos. Las pruebas se dividirán de la siguiente manera:

  1. Para explicar los test unitarios se tiene un método en la capa de aplicación un método que recibe el nombre y apellido de una persona y lo regresa concatenado, teniendo varientes si se ha ingreso el nombre o el apellido en vacio.
  2. Probaremos el mocking simulando que estamos accediendo al repositorio y desde este a una base de datos en donde obtenemos un listado de nombres de personas.
Capa de aplicación
Capa de repositorio

En el proyecto de test unitarios, se crearon los siguientes test unitarios:

  • El primero prueba el escenario ideal del método que desarrollamos, notemos que en la primera parte de nuestro test, estamos preparando la información, liego consumimos el método desarrollado y finalmente evaluamos el resultado con los assert que nos brinda xunit.
  • En el segundo test unitario, probamos el escenario en el que a nuestro método no se le proporcione la información necesaria. Se sigue el mismo formato con la organización de los pasos para las pruebas (preparar la información, llamar al método y finalmente evaluar los resultados).
  • Para realizar la prueba del mocking, es importante realizar la inyección de dependencia del repositorio en nuestra aplicación, dado que lo que buscamos con el mocking es poder simular el acceso en este repositorio, Luego, en el test creamos el mock con la interfaz de nuestro repositorio, le indicamos en “Setup” con una expresión lambda el método que vamos a probar, y en este punto podríamos proporcionale la información que sea necesaria para consumir este método de ser esto necesario y finalmente le indicamos lo que va a retornar, para conseguir esto hemos debido crear un objeto del mismo tipo que retorna nuestro método y indicarlo dentro de “Returns”. Finalmente, le pasamos nuestro mock al construtor de nuestra aplicación y llamamos al método a probar.
Inyección de dependencia
Mocking usando moq en NetCore

Finalmente, corremos nuestros test unitarios y tenemos el siguiente resultado:

Como podemos ver, lo importante del test unitario es poder realizar pruebas atómicas del código que escribimos y con esta finalidad quitarle la responsabilidad como obtener objetos que escapan a lo que buscamos probar (como conexiones a base de datos o otros métodos). Y con esta finalidad nos apoyamos del mocking, existen muchas cosas más que se pueden llevar a cabo con Xunit, e incluso más con Moq, ambas librerías usadas para esta demo, Más adelante realizaré más post en los cuales detallo un poco las características de ambas, espero que encuentren útil el post, les dejo el video y el link de github del proyecto realizado.

REPO: GITHUB

Saludos.

Deja un comentario

Caching en Web API Net Core 2.2

Para nadie es sorpresa que la tendencia en el desarrollo con tencologias Backend de Microsoft se orienta cada vez más a NetCore, estando como release candidate (a la fecha de hoy) la versión 3.0.

Hace un tiempo que vengo trabajando con NetCore, inicialmente en proyectos personales y luego en el trabajo. El tema que hoy nos reclama es como aplicar caching y concurrency en las web api cuando se trabaja con Net Core. Para ello, primero recordemos un poco que implica caching.

Cuando nos referimos a caching es válido entender que brindamos un determinado tiempo de vida a una solicitud http, lo cual nos permite no volver a consultar el mismo recurso por el tiempo que se ha determinado, esto nos permite optimizar los tiempos de respuesta y el consumo de recursos en el servidor.

Existen tipos de caching, para entender mejor esta idea, revisemos la siguiente imagen:

caching types

  • Client Cache: Usualmente podemos encontrarlos en el navegador, almacenan las respuestas de las peticiones http individualmente si estas así lo indican, es privado porque los recursos que se están almacenando no se comparten con nadie más.
  • Gateway Cache: Es un cache compartido, los recursos son usados por multiples aplicaciones.
  • Proxy Cache: Tambien es un cache compartido, sin embargo su embergadura es mayor, es usualmente usado por corporaciones grandes o provedores de internet.

Del mismo modo, cuando se trabaja con caching, tenemos que tener un poco más claro que significa el “Modelo de expiración”, esta es una forma de indicarle a los clientes, cuanto tiempo va a durar una solicitud, lo cual permite indicarle a las aplicaciones clientes por cuanto tiempo se va a entender que una respuesta http se considera activa. Para conseguir este objetivo se usan dos header comunmente:

  • Expires Hader: Es el más simple, contiene una marca de tiempo de la expiración, pero se asume que las horas entre el cliente y el servidor están sincronizadas.
  • Cache Control Header: Permite indicar el tiempo como “max-age” lo cual indica estará activo por 60 segundos, y public indica quienes pueden realizar el caching de esta respuesta http (client, gateway o proxy).

Es necesario hablar también sobre los modelos de validación o “Validation Model” , estos nos permiten validar si la solicitud http ha sido modificada y de este modo mantenemos la integridad de nuestra solicitud.

  • Strong Validators: Usan los “ETag” para validar si la respuesta ha sido modificada.
  • Weak Validators: No siempre cambian cuando la respuesta lo hace, sólo cambian en cambios considerables, se basan en una etiqueta de “Last-Modified”, recordemos que los horarios deben estar sincronizados. También poseen weak Etag.

Finalmente, para culminar con la teoría, es necesario hablar sobre “Cache-control directives”, las cuales son las directivas que se pueden enviar en el request y el response http:

  • Response: Tenemos elementos de control que nos indican el tiempo de duración máximo (en segundos) de la solicitud, si es posible almacenarla en el navegador (private) o en el servidor (public) entre otras.
  • Request: Del mismo modo, tenemos elementos que nos valida el tiempo de duración de la respuesta mínimo y máximo entre otras.

Para la demo que vamos a realizar, usaremos un nugget llamado “Marvin.Cache.Headers”, luego de instalarlo nos dirigimos al archivo de configuración “Startup” de nuestro web api.

Es necesario agregar en el “ConfigurationService” y en el “Configure” que se debe añadir el uso de cacheheader al pipeline de ejecución, adicionalmente estoy sobreescribiendo el timepo de expiración de la solicitud e indicandole que se debe revalidar.

Sólo con está configuración, ya tenemos habilitado el uso de caching, en su modo más básico. Probemos en postman el uso de lo implementado, primero debemos habilitar el envío de “cache-control” en el header, esto se hace de la siguiente manera:

La petición que llevaremos a cabo, es la siguiente:

Como pueden ver es un GET a un endpoint que en el query esta buscando los libros de un determinado autor. Pongamos un punto de interrupción para validar que la petición a llegado, y veamos la respuesta que recibimos.

Como podemos ver, el tiempo de vida de la petición es 30 segundos, de modo que si se volviera a hacer otra petición, esta no llegaria a nuestro endpoint, en cambio nos indicaria el timepo de vida que aún tiene la solicitud que hemos realizado.

Les dejo link al repositorio en github en el cual pueden encontrar el proyecto completo y el video de youtube donde pueden visualizar las pruebas.

REPO: GITHUB

Saludos.

Deja un comentario