2. Quarkus: yet another framework like Spring Boot

2. Quarkus: yet another framework like Spring Boot

This is the 2nd blog as part of the series Full Stack: Remastering Master Data Management into graph like data. Hope you enjoy the series and find it useful !!

Introduction

As discussed in our introductory part of the series, we are planning to create a data lake. On the journey to the ultimate destination, we will be creating multiple micro-services and we will walk through various technologies being used. So the first stepping stone of the journey is to write some basic code to access the data from a relational database.

We often have used and wrote code in and around Spring Boot. It has brought lot of ease into our life with its vast usage of simple annotations and integration with various technologies. Nowadays, its pretty common to write an application and deploy to the cloud and not worry about the infrastructure. In this type of environment, where instances are created and destroyed frequently, the time to boot and time to first request are extremely important, as they can create a completely different user experience. Languages as JavaScript and Python are always in the spotlight in this type of scenario. In other words, Java with its fat JARs and long booting time was never a top contender.

Quarkus, the Supersonic Subatomic Java, promises to deliver small artifacts, extremely fast boot time, and lower time-to-first-request. And since Quarkus is built on top of existing standards, we dont need to learn anything new. We can still use JAX-RS, CDI, Hibernate, Kafka, Vert.X, etc. as mentioned in their Get Started page.

Quarkus technologies

So lets start with initiating our application.

Bootstrap Our First Application

We can create a bundle from Official Get Started page of Quarkus by selecting various extensions from its ecosystem. But the most easiest way to create a new project is to open a terminal and type:

mvn io.quarkus:quarkus-maven-plugin:1.4.2.Final:create \
    -DprojectGroupId=com.practice \
    -DprojectArtifactId=graph-based-data-lake \
    -DclassName="com.practice.UserController" \
    -Dpath="/users"

First REST API to fetch data

Now once everything is set, lets add some basic libraries. Since we are planning to write a simple REST API, we will need JAX-RS implementation and Hibernate to connect to database. Our data is stored in a basic MySQL database in a relational format which means we have an Entity table and a Relation table in order to make a link with any other entity. I am going to play around Identity and Access Management related data.

We will select RESTEasy, Hibernate ORM with Panache and off course JDBC Driver - MySQL to connect to MySQL Database.

So lets write our basic controller:

@Path("/users") // Annotation to define path
@ApplicationScoped // Specifies that the bean is application scoped
@RegisterForReflection // To force a class to be registered for reflection in native image mode
public class UserController {

    @Inject // Dependency injection like Autowired
    UserRepository userRepo;

    @Path("/all")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllUsers() {
        List<User> users = userRepo.listAll();
        return Response.ok(users).build();
    }

}

A basic Repository code would look like:

@ApplicationScoped
public class UserRepository implements PanacheRepository<User> {
    // put your custom logic here as instance methods

   public User findByName(String name){
       return find("name", name).firstResult();
   }

   public void deleteStefs(){
       delete("name", "Stef");
  }
}

A basic model would look like:

@Entity
@Table(name = "entity_identity")
public class User {

    @Id
    @Column(name = "entity_unique_id")
    private String id;
    @Column(name = "identity_name_given")
    private String firstName;
    @Column(name = "identity_name_middle")
    private String middleName;
    @Column(name = "identity_name_family")
    private String lastName;
    @Column(name = "identity_email")
    private String email;
    @Column(name = "identity_photo")
    private String photo;
    @Column(name = "persona_id")
    private String employeeId;
    @Column(name = "persona_title")
    private String employeeTitle;
    @Column(name = "persona_type")
    private String employeeType;
    @Column(name = "persona_status")
    private String employeeStatus;
    @Column(name = "persona_organization")
    private String employeeOrganization;
}

Same as like Spring Boot, it allows you define the application.properties. So, in order to connect to database, we will use the following config:

# Configuration file
# key = value
#
# Quarkus
#
quarkus.log.file.enable=false

#
# Quarkus :: DS
#
quarkus.datasource.db-kind=mysql
quarkus.datasource.jdbc.url=jdbc:mysql://127.0.0.1:3306/practice
quarkus.datasource.jdbc.driver=com.mysql.cj.jdbc.Driver
quarkus.hibernate-orm.dialect=org.hibernate.dialect.MySQL8Dialect
quarkus.datasource.username=root
quarkus.datasource.password=password

#
# Logging
#
quarkus.hibernate-orm.log.sql=true
quarkus.log.level=INFO

That's it ! Now you can run this application easily by running the below command:

./mvnw compile quarkus:dev

Now you will be able to call localhost:8080/users/all and get all the users listed from your database.

Also with the power of GraalVM and OpenJDK Hotspot, it provides the usage of Hot Reload capability. In other words, changes made to Java files or to configuration files will automatically be compiled once the url is refreshed. The most impressive feature here is that we don't need to save our files.

Supersonic feature

Lets try packaging

We can easily package the application by running:

./mvnw package

This will generate 2 jar files inside the target directory:

  • graph-based-data-lake-1.0-SNAPSHOT-runner.jar — an executable jar with the dependencies copied to target/lib
  • graph-based-data-lake-1.0-SNAPSHOT.jar — contains classes and resource files

which you can run by using:

java -jar target/quarkus-project-1.0-SNAPSHOT-runner.jar

Secondly, we'll create a container image using our native executable. For that, we must have a container runtime (i.e. Docker) running in our machine. Let's open up a terminal window and execute:

./mvnw package -Pnative -Dnative-image.docker-build=true

The project generation will create a Dockerfile.native for us. If you read the comments it gives a hint that we need to create build that image using:

docker build -f src/main/docker/Dockerfile.native -t quarkus/graph-data-lake .

And finally we can run the container using:

docker run -i --rm -p 8080:8080 quarkus/graph-data-lake

Source Code

Lets try to add more Entities and their REST APIs. You can find the source code in:

.