Implementación del Patrón Repository en Quarkus
- Carlos Brignardello
- 07 Jun, 2024
¿Qué es el Patrón Repository?
El Patrón Repository es un patrón de diseño cuyo objetivo principal es encapsular la lógica de acceso a datos, permitiendo una separación clara entre la lógica de negocio y la capa de persistencia. Este patrón actúa como un intermediario entre la aplicación y la base de datos, proporcionando una abstracción sobre la implementación concreta del acceso a datos.
Beneficios del Patrón Repository
- Encapsulamiento de la lógica de acceso a datos: Centraliza la lógica de acceso a datos, facilitando el mantenimiento y la modificación.
- Facilita las pruebas unitarias: Al abstraer la lógica de acceso a datos, es más sencillo simular la base de datos durante las pruebas.
- Mejora la organización del código: Separa las preocupaciones de negocio y persistencia, promoviendo un diseño más limpio y modular.
Repositorio: https://github.com/vrignardello/quarkus-repository-pattern-example
Estructura del Proyecto
Para implementar el Patrón Repository, crearemos un directorio repository
donde cada entidad tendrá su propio archivo repository. Este enfoque facilita la organización y mantenimiento del código, ya que la lógica de acceso a datos estará separada de la lógica de negocio.
En Quarkus, la estructura básica incluirá los siguientes componentes:
- Controller: Controla las solicitudes HTTP y las respuestas.
- Service: Contiene la lógica de negocio y llama a los métodos del repository.
- Repository: Maneja la interacción directa con la base de datos.
- Model: Representa las entidades de la base de datos.
Iniciar Proyecto Quarkus
Accede a Quarkus y selecciona las siguientes dependencias:
- Hibernate ORM With Panache (
io.quarkus.hibernate.orm.panache
): Simplifica el acceso a datos con Panache. - Rest Jackson (
quarkus-rest-jackson
): Maneja respuestas JSON. - JDBC Driver — PostgreSQL (
quarkus-jdbc-postgresql
): Interactúa con una base de datos PostgreSQL.
Descarga el ZIP e inicia el proyecto.
Agregar Dependencia Lombok
Añade Lombok para simplificar el uso de getters y setters:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
</dependency>
Instalar las Dependencias
Como instalamos Lombok por fuera del initializer de Quarkus debemos ejecutar el siguiente comando para instalar las dependencias:
mvn install
Crear Imagen PostgreSQL con Docker
Dockerfile
Crea un archivo Dockerfile con el siguiente contenido:
# Usa la imagen base de PostgreSQL
FROM postgres:latest
# Variables de entorno
ENV POSTGRES_USER=root
ENV POSTGRES_PASSWORD=root
# Puerto expuesto
EXPOSE 5432
# Volumen para los datos de PostgreSQL
VOLUME /var/lib/postgresql/data
Construir la Imagen
Construye la imagen Docker con el siguiente comando:
docker build -t postgres-db .
Verificar Puertos
Antes de ejecutar el contenedor, verifica que el puerto 5432 esté disponible:
netstat -ano | findstr "5433"
Ejecutar Contenedor
Ejecuta el contenedor Docker:
docker run --name repository-db -dp 5433:5432 postgres-db
Configuración en application.properties
Configura tu aplicación para conectarse a la base de datos:
quarkus.datasource.db-kind=postgresql
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5433/postgres
quarkus.datasource.username=root
quarkus.datasource.password=root
quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.log.sql=true
Implementación del Patrón Repository
Entidad JPA
Las entidades JPA representan las tablas en la base de datos. Definiremos una clase TaskEntity
para representar una tarea en nuestra aplicación. Esta clase incluirá atributos como id
, name
, description
y comment
. Usaremos anotaciones JPA para mapear esta clase a una tabla en la base de datos.
package vrigna.tasks.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "Task")
@Getter
@Setter
public class TaskEntity {
@Id
@GeneratedValue
private Long id;
private String name;
private String description;
private String comment;
}
Controlador
El controlador maneja las solicitudes HTTP y devuelve las respuestas. Crearemos una clase TaskController
que define endpoints para agregar una tarea y listar todas las tareas. Usaremos anotaciones para mapear las rutas y los métodos HTTP.
package vrigna.tasks.controller;
import java.util.List;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Response;
import vrigna.tasks.entity.TaskEntity;
import vrigna.tasks.service.TaskService;
@Path("/api/v1/task")
public class TaskController {
@Inject
TaskService taskService;
@POST
@Path("/")
public Response add(TaskEntity task) {
TaskEntity taskEntity = taskService.add(task);
return Response.ok(taskEntity).build();
}
@GET
@Path("/")
public Response listAll() {
List<TaskEntity> taskEntities = taskService.listAll();
return Response.ok(taskEntities).build();
}
}
Servicio
El servicio contiene la lógica de negocio y llama a los métodos del repositorio. Definiremos una clase TaskService
con métodos para agregar una tarea y listar todas las tareas. Esta clase se anotará con @ApplicationScoped
para que Quarkus maneje su ciclo de vida.
package vrigna.tasks.service;
import java.util.List;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import vrigna.tasks.entity.TaskEntity;
import vrigna.tasks.repository.TaskRepository;
@ApplicationScoped
@Transactional
public class TaskService {
@Inject
TaskRepository taskRepository;
public TaskEntity add(TaskEntity taskEntity) {
taskRepository.persist(taskEntity);
return taskEntity;
}
public List<TaskEntity> listAll() {
return taskRepository.listAll();
}
}
Repositorio
El repositorio maneja la interacción directa con la base de datos. En Quarkus, usaremos Panache, una biblioteca que simplifica las operaciones de JPA. Crearemos una clase TaskRepository
que implementa PanacheRepositoryBase
para manejar las operaciones CRUD básicas.
package vrigna.tasks.repository;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped;
import vrigna.tasks.entity.TaskEntity;
@ApplicationScoped
public class TaskRepository implements PanacheRepositoryBase<TaskEntity, Long> {
}
Conclusión
Con estos pasos, hemos creado una aplicación Quarkus que implementa el Patrón Repository para manejar la persistencia de datos de manera eficiente y organizada. Este enfoque facilita el mantenimiento y la escalabilidad del código.