Implementación del Patrón Repository en Quarkus

Implementación del Patrón Repository en Quarkus

¿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.

Tutorial en YouTube