Power of Redis®* for your supersonic Quarkus/Java application
Tags: quarkus, aiven, opensource, redis
Published: 2022-08-10 14:15:23

---
title: Power of Redis®* for your supersonic Quarkus/Java application
published: true
description: Traditional Java apps are notorious for being large and slow to start. Read on to see how to use Quarkus and Redis®* to make a Kubernetes-friendly Java app.
canonical_url: https://aiven.io/blog/redis-and-quarkus-app
---

When building applications that run on Kubernetes, you want the start-up time and footprint to be small. Traditional Java applications like to consume more than their constrained memory and CPU and you might have seen `OOMKilled` errors in your production applications. Brace yourself as this blog takes you on a "supersonic" journey with [Quarkus](https://quarkus.io/) (a fast and lightweight Java framework) and Redis®* (fast in-memory data structure store). 

### Building a small one-time-password application

Imagine that you're building a one-time-password feature as part of a larger project. Your team is using Java, which they're familiar with, and Quarkus as the framework because they want the application to be Kubernetes-compatible (in terms of size and startup time). 

Besides a relational database, the team is also using Redis for fast querying of the generated one-time-passwords. This example uses [Aiven for Redis](https://aiven.io/redis) and you can [sign up for a free trial](https://console.aiven.io/signup) if you want to try it out.   

An important consideration for your team is that both Quarkus and Redis are open-source projects.

### Before you start

To follow the hands-on portion of this blog, here are the software requirements:

- [JDK 11+](https://openjdk.java.net/install/) 
- [Apache Maven 3.8.1+](https://maven.apache.org/install.html)
- A [local](https://redis.io/download/) or [managed](https://aiven.io/redis) Redis instance 

### Time to build the app

#### Create a Maven Project

The following command creates a new Maven project and adds the required extensions to your project. The Quarkus `redis-client` extension allows the user to connect to a Redis server and run Redis commands. The `resteasy-jackson` extension allows to build RESTful web services and to process JSON data format. The `resteasy-mutiny` extension helps to build reactive APIs for asynchronous systems. 

```
mvn io.quarkus.platform:quarkus-maven-plugin:2.7.5.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=one-time-password \
    -Dextensions="redis-client,resteasy-jackson,resteasy-mutiny" \
    -DnoCode
cd one-time-password
```

Use the following command to add the `redis-client` dependency to your `pom.xml` file:

```
./mvnw quarkus:add-extension -Dextensions="redis-client"
```

#### Getting the Redis server details

Create an [Aiven for Redis](https://developer.aiven.io/docs/products/redis/get-started.html) instance. For this exercise, any service plan will do. Once the Redis service is running, copy the **Service URI** from the *Overview* > *Connection information* tab. 

Go to your favorite code editor and open the `one-time-password` project. Paste the **Service URI** to the `src > main > resources > application.properties` file:

```
quarkus.redis.hosts=[YOUR REDIS CONNECTION INFORMATION GOES HERE]
```

If you're running Redis on your local machine, use the following settings:

```
quarkus.redis.hosts=redis://localhost:6379 
```

#### Create the Otp POJO (Plain Old Java Object)

The `Otp` class creates a POJO (Plain Old Java Object) to hold the `session_key` and `otp_value`. The `generateRandomOtp` method generates a random value within a given range. 

Create the `src/main/java/org/acme/redis/Otp.java` file and add the following:

```
package org.acme.redis;
import java.util.Random;

public class Otp {
    final int lowRange = 100000;
    final int highRange = 999999;
    public String session_key;
    public int otp_value;

    public Otp(String session_key) {
        this.session_key = session_key;
        this.otp_value = generateRandomOtp(lowRange, highRange);
    }

    public Otp() {}

    private static int generateRandomOtp(int low, int high) {

        // Generate random int value from $low to ($high - 1)
        return low + new Random().nextInt(high - low);
    }
}
```

#### Create the Otp Service

You are going to create the `OtpService` which will play the role of a Redis client. This class will help you perform the `GET`, `EXISTS`, `SETEX`, `SETNX`, and `TTL` Redis commands. For documentation on these see the [official Redis commands page](https://redis.io/commands/).

Create the `src/main/java/org/acme/redis/OtpService.java` file and add the following:

```
package org.acme.redis;
import io.quarkus.redis.client.RedisClient;
import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Singleton;

@Singleton
class OtpService {
    final int timeInSeconds = 20;

    @Inject
    RedisClient redisClient;

    public String getOtp(String session_key) {
        return redisClient.get(session_key).toString();
    }

    public void newOtp(String session_key) {
        Otp otp = new Otp(session_key);

        // SETNX will only create a key if it doesn't already exist
        // - so we won't overwrite an existing OTP value
        // Unfortunately SETNX can't set the TTL/expiration time
        if (redisClient.setnx(otp.session_key.toString(),
                String.valueOf(otp.otp_value)).toBoolean()) {

            // Only update TTL/expiration if the OTP value was set
            redisClient.setex(otp.session_key.toString(),
                String.valueOf(timeInSeconds),
                String.valueOf(otp.otp_value));
        }
    }

    public String getOtpTTL(String session_key) {
        return redisClient.ttl(session_key).toString();
    }

    public boolean keyExists(String session_key) {
        return redisClient.exists(Arrays.asList(session_key)).toBoolean();
    }
}
```

#### Create the Otp Resource

Create the `src/main/java/org/acme/redis/OtpResource.java` file where you define the HTTP endpoints for your one-time-password service. 

Observe the `@Inject` annotation to easily create the service instance and `@Path("/otp")` to indicate the creation of the HTTP endpoints. The same endpoint is used for both `GET` and `POST` calls. The great thing of using a framework like Quarkus is that without the annotations, you would have to write multiple lines of code to achieve the same outcome.

```
package org.acme.redis;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jboss.resteasy.annotations.jaxrs.QueryParam;
import io.vertx.core.json.JsonObject;

@Path("/otp")
public class OtpResource {
    @Inject
    OtpService service;

    @GET
    public JsonObject getOtp(@QueryParam String session_key) {
    
        // If the key doesn't exist, return an error response rather than the usual
        // object response
        if (!service.keyExists(session_key)) {
            return errorResponse();
        }
        JsonObject result = new JsonObject();
        result.put("OTP: ", service.getOtp(session_key));
        result.put("TTL: ", service.getOtpTTL(session_key));
        return result;
    }

    JsonObject errorResponse() {
        JsonObject result = new JsonObject();
        result.put("Message: ", "The OTP key doesn't exist.");
        return result;
    }

    @POST
    public void newOtp(@QueryParam String session_key) {
        service.newOtp(session_key);
    }
}
```

### Run your new Quarkus app

From the root of your one-time-password project, execute the following command:

```
 ./mvnw quarkus:dev
```

Navigate to `http://localhost:8080/otp?session_key=[SOME_KEY]`, replacing `[SOME_KEY]` with any text. For your initial run, you'll receive an error response like this:

```
"Message: ": "The OTP key doesn't exist."
```

This is because this key doesn't exist in Redis yet. From your terminal, make the following *POST* request to create your key:

```
curl --location --request POST 'http://localhost:8080/otp?session_key=[SOME_KEY]'
```

Now reload your browser and you should receive a random 6-digit number as a one-time-password that expires in 20 seconds. If you wait more than 20 seconds, it will expire and you'll receive the error response again. 

If you keep refreshing the page, you'll be getting the same OTP until the (time-to-live) TTL  runs out.

You might also realize that you didn't have to do any server setup/handling for this application as Quarkus took care of that for you. Pretty cool, eh?

### Further learning

In this blog, I provided you with a getting started experience with Redis and demoed a use case by building a simple one-time-password application using the Quarkus framework. The design and implementation of actual one-time-password software is far more complex than the simple application mentioned here; for instance, it would probably not want to give the same OTP to different users.  

To learn more about Quarkus:

- [Quarkus project documentation](https://quarkus.io/)

To learn more about Redis:

- [Redis documentation](https://redis.io/docs/)
- [Aiven for Redis - Developer Documentation](https://developer.aiven.io/docs/products/redis/)


_*Redis is a registered trademark of Redis Ltd. and the Redis box logo is a mark of Redis Ltd. Any rights therein are reserved to Redis Ltd. Any use by Aiven is for referential purposes only and does not indicate any sponsorship, endorsement or affiliation between Redis and Aiven. All product and service names used in this website are for identification purposes only and do not imply endorsement._