Java Quarkus: API REST Cache
Ejemplo Api REST con Cache, ORM y base de datos PostgreSql
Java Quarkus incorpora una extensión para almacenamiento en cache local bastante práctica para aplicaciones que no requieran cache distribuida, pero que necesiten mejoras de rendimiento y velocidad de respuesta.
En el archivo 'pom.xml' se definen las dependencias para la gestión del cache local, servicios REST Json, ORM Panache y el driver de base de datos (PostgreSQL):
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-cache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
En el archivo 'application.properties' se configuran los parámetros de tamaño inicial y maximo del cache, junto al tiempo de expiración de una entrada luego de ser registrada en el cache local.
quarkus.cache.caffeine."cache-users".initial-capacity=20
quarkus.cache.caffeine."cache-users".maximum-size=300
quarkus.cache.caffeine."cache-users".expire-after-write=300S
Agregamos una clase entidad sencilla (User) y una clase 'repositorio' para temas de persistencia:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private Long id;
@Column(unique = true)
private String documentId;
private String firstName;
private String lastName;
@Enumerated(EnumType.STRING)
private Gender gender;
private String emailAddress;
private String phoneNumber;
public User() {
}
// getters ..
// setters ..
}
@ApplicationScoped
public class UserRepository implements PanacheRepository<User> {
public Optional<User> findByDocumentId(String documentId) {
return find("documentId", documentId).firstResultOptional();
}
public Optional<User> findByEmail(String email) {
return find("emailAddress", email).firstResultOptional();
}
}
La clase encargada de implementar el servicio de cache tiene el siguiente aspecto:
@ApplicationScoped
public class UserService {
private static final Logger log = Logger.getLogger(UserService.class);
@Inject
private UserRepository userRepository;
@CacheResult(cacheName = "cache-users")
public Optional<User> fetchUser(String documentId) {
if (Optional.ofNullable(documentId).isEmpty()) return Optional.empty();
log.infof("[x] find entity by documentId: %s", documentId);
return userRepository.findByDocumentId(documentId.strip());
}
@Transactional
@CacheInvalidate(cacheName = "cache-users")
public boolean deleteUser(String documentId) {
if (Optional.ofNullable(documentId).isEmpty()) return false;
Optional<User> user = userRepository.findByDocumentId(documentId.strip());
if (user.isPresent()) {
log.infof("[x] delete entity with documentId: %s", documentId);
return userRepository.deleteById(user.get().getId());
}
return false;
}
}
La anotación '@CacheResult' indica el nombre del cache configurado en el archivo de propiedades ('cache-users'). Con esto el valor retornado sera el almacenado en el cache (de existir) sin ejecutar el código de nuestro método.
La anotación '@CacheInvalidate' se utiliza para quitar explícitamente una entrada del cache.
La clase que consume el servicio luce de la siguiente forma:
@Path("/")
public class UserRest {
@Inject
private UserService userService;
@GET
@Path("/api/v1/lab/users/{documentId}")
public Response findByDocumentId(@PathParam String documentId) {
Optional<User> user = userService.fetchUser(documentId);
if (user.isPresent())
return Response.ok(user.get()).build();
return Response.status(Response.Status.NOT_FOUND).build();
}
@DELETE
@Path("/api/v1/lab/users/{documentId}")
public Response delete(@PathParam String documentId) {
boolean delete = userService.deleteUser(documentId);
if (delete)
return Response.ok().build();
return Response.status(Response.Status.NOT_FOUND).build();
}
}
Puedes descargar el código fuente completo de este ejemplo en el siguiente enlace.
¿Tienes alguna consulta?
Puedes contactarme enviándome un mensaje desde aquí.

diciembre 16, 2022 Backend

septiembre 19, 2022 Redes/Networking, Embedded Systems

julio 20, 2022 Cloud
- Backend(4)
- Redes/Networking(4)
- Embedded Systems(2)
- Cloud(2)
- Frontend(3)
- Microservicios(4)