DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Efficient Data Management With Offset and Cursor-Based Pagination in Modern Applications
  • New ORM Framework for Kotlin
  • Pessimistic and Optimistic Locking With MySQL, jOOQ, and Kotlin
  • The Generic Way To Convert Between Java and PostgreSQL Enums

Trending

  • How to Format Articles for DZone
  • Strategies for Securing E-Commerce Applications
  • Simplifying Multi-LLM Integration With KubeMQ
  • Optimizing Serverless Computing with AWS Lambda Layers and CloudFormation
  1. DZone
  2. Data Engineering
  3. Databases
  4. Think Reactive and Native With Quarkus, Kotlin, and GraphQL

Think Reactive and Native With Quarkus, Kotlin, and GraphQL

Native applications are an essential factor in containerization. Reactive programming is an excellent choice for developing stream-based or queue-based applications

By 
Ashok Gudise user avatar
Ashok Gudise
·
Mar. 03, 23 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
5.7K Views

Join the DZone community and get the full member experience.

Join For Free

Introduction

In today’s world of software development, the terms “native” and “reactive” have gained significant popularity, becoming crucial considerations for developers, architects, and businesses alike.

Regardless of whether you’re building front-end applications or back-end systems, the native and reactive approach has become a crucial component of modern software development’s non-functional requirements. This blog aims to explore the significance of these two concepts and why they have become so essential.

We will also take a closer look at where these two concepts will fit in the three main categories of prevalent software solutions in the IT industry today: Request-Response (Synchronous), queue-based (Asynchronous), and event-based (Streams/Event Sourcing). Finally, we will examine how native and reactive architectures can bring significant benefits to each of these categories.

About “Native”

Containerization has become a popular approach to deploying applications in modern cloud environments. With containers, applications are packaged into a single container image, which can then be deployed across different environments consistently. However, when it comes to running applications in containers, there are two main options: running as a traditional virtual machine (VM) or running as a native application. Native applications are built specifically for the target platform, resulting in better performance, faster startup times, lower memory consumption, and better runtime performance. They can be easily scaled horizontally, increasing resource utilization efficiency. Additionally, running applications natively reduces the attack surface area, making the application more secure. In summary, native applications are an essential factor in containerization, providing better performance, scalability, resource efficiency, and security, and are crucial for the success of modern cloud environments. You can learn more about Cloud-Native here.

About “Reactive”

Reactive programming has gained popularity in recent years, and for good reason. One significant benefit of reactive programming is its ability to handle stream-based or queue-based applications. In such applications, the processing of incoming messages or events is time-sensitive and requires immediate action. Reactive programming provides a solution for these scenarios by allowing the developer to write applications that can react immediately to incoming events rather than waiting for a response from the previous event. This means that the application can handle high volumes of incoming data without blocking, resulting in a faster and more efficient application. Additionally, reactive programming allows for better scalability and resilience, as it can handle large amounts of incoming data without overloading the system. In summary, reactive programming is an excellent choice for developing stream-based or queue-based applications, as it allows for immediate response and efficient handling of high volumes of data, resulting in a more scalable, resilient, and performant application.

Tech Stack

Quarkus is an emerging alternative to the Spring framework from RedHat. It is rapidly gaining popularity due to its high performance and efficient resource usage. One of the key reasons for its popularity is its ability to use a compile-time approach to build native apps, resulting in lightweight and fast apps. This approach, coupled with Quarkus’ support for GraalVM, allows Quarkus apps to consume minimal resources, making them ideal for running in resource-constrained environments like containers or serverless environments.

Quarkus also provides a streamlined development experience for developers, with extensive development tools and hot reloading support. Quarkus is designed to work well with cloud-native architectures and provides out-of-the-box support for several cloud-native technologies like Kubernetes, Istio, and Knative.

Quarkus Reactive is a powerful framework for building reactive applications, with features like Panache that make it easy to work with databases like MySQL using plain old Java objects (POJOs). With Panache, developers can create entities that map to database tables and perform CRUD operations using simple, type-safe methods.

In summary, Quarkus is an excellent alternative to the Spring framework, providing several advantages such as high performance, efficient resource usage, cloud-native support, and a streamlined development experience, making it an ideal choice for modern cloud-native architectures.

Kotlin: is a statically typed programming language that was designed to be more concise and expressive than Java while still being fully interoperable with Java code. Developed by JetBrains, Kotlin is open source and has rapidly gained popularity due to its ease of use, concise syntax, and improved developer productivity. Kotlin is used for developing a wide range of applications, from Android mobile apps to server-side applications and beyond. Its adoption has been driven by major companies like Google, Netflix, and Pinterest, making Kotlin a popular choice among developers for modern software development.

GraphQL: Developed by Facebook, GraphQL is a query language for APIs that has since been made available to the wider developer community. It offers a more efficient, powerful, and flexible option compared to REST for modern web APIs. With GraphQL, you can specify the exact data you need, reducing issues of over-fetching and under-fetching. Key features are Mutations and GraphQL-UI that come along with your API.

Demo Scene

Suppose that AWS Cloud does not offer its crucial “Reliability” pillar, and you are responsible for managing your app (EC2 instances/pods) independently. Your task is to create an API that is reactive, which means you need to receive real-time notifications when a pod is terminated or created. Let us develop the API to fulfill these essential requirements.

— Even if it’s just a hypothetical scenario, it can still be alarming to consider the potential challenges and risks that may arise in such a situation 

Database Schema

Define the main components of AWS Network like VPC, Region, Subnet, EC2, etc.

SQL
 
CREATE TABLE region (
                        region_id INT NOT NULL AUTO_INCREMENT,
                        region_name VARCHAR(255) NOT NULL,
                        PRIMARY KEY (region_id)
);

CREATE TABLE vpc (
                     vpc_id INT NOT NULL AUTO_INCREMENT,
                     vpc_name VARCHAR(255) NOT NULL,
                     region_id INT NOT NULL,
                     PRIMARY KEY (vpc_id),
                     FOREIGN KEY (region_id) REFERENCES region(region_id)
);

CREATE TABLE azone(
                      az_id INT NOT NULL AUTO_INCREMENT,
                      az_name VARCHAR(255) NOT NULL,
                      region_id INT NOT NULL,
                      PRIMARY KEY (az_id),
                      FOREIGN KEY (region_id) REFERENCES region(region_id)
);

CREATE TABLE subnet (
                        subnet_id INT NOT NULL AUTO_INCREMENT,
                        subnet_name VARCHAR(255) NOT NULL,
                        vpc_id INT NOT NULL,
                        az_id INT NOT NULL,
                        PRIMARY KEY (subnet_id),
                        FOREIGN KEY (vpc_id) REFERENCES vpc(vpc_id),
                        FOREIGN KEY (az_id) REFERENCES azone(az_id)
);

CREATE TABLE ec2 (
                     ec2_id INT NOT NULL AUTO_INCREMENT,
                     ec2_name VARCHAR(255) NOT NULL,
                     subnet_id INT NOT NULL,
                     PRIMARY KEY (ec2_id),
                     FOREIGN KEY (subnet_id) REFERENCES subnet(subnet_id)
);


Now, Let’s create a Quarkus Project by using IntelliJ Idea’s Project Initializer, or you can simply visit the official website and create it.

New Project

Project Initializer

Project Initializer

Modules

Modules


Define Your Entity Classes

Kotlin
 
@Entity
@Cacheable
@Table(schema = "sysopsdb", name="azone")
class Azone {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="az_id")
    var id: Long? = null

    @Column(name ="az_name")
    lateinit var name: String

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "region_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    var region: Region? = null

    @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, mappedBy = "azone")
    var subnets: Set<Subnet> = HashSet<Subnet>()

}

@Entity
@Cacheable
@Table(schema = "sysopsdb", name="ec2")
class EC2{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="ec2_id")
    var id: Long? = null

    @Column(name ="ec2_name")
    lateinit var name: String

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "subnet_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    var subnet: Subnet? = null
}

@Entity
@Cacheable
@Table(schema = "sysopsdb", name="region")
class Region {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="region_id")
    var id: Long? = null

    @Column(name ="region_name")
    lateinit var name: String

    @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, mappedBy = "region")
    val azs: Set<Azone> = HashSet<Azone>()
}

@Entity
@Cacheable
@Table(schema = "sysopsdb", name="subnet")
class Subnet {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="subnet_id")
    var id: Long? = null

    @Column(name ="subnet_name")
    lateinit var name: String

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "vpc_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    val vpc: VPC? = null

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "az_id", nullable = false)
    @OnDelete(action = OnDeleteAction.CASCADE)
    val azone: Azone? = null

    @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, mappedBy = "subnet")
    val ec2s: Set<EC2> = HashSet<EC2>()
}

@Entity
@Cacheable
@Table(schema ="sysopsdb", name = "vpc")
class VPC {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name ="vpc_id")
    var id: Long? = null

    @Column(name ="vpc_name")
    lateinit var name: String

}


Panache Repositories

Kotlin
 
@ApplicationScoped
class AzoneRepository: PanacheRepository<Azone> {
    fun findByName(name: String) = find("name", name).firstResult<Azone>()
    fun deleteInstance(id: Long) = delete("id", id)
}

@ApplicationScoped
class EC2Repository: PanacheRepository<EC2> {
    fun findByName(name: String) = find("name", name).firstResult<EC2>()
    fun deleteInstance(id: Long) = delete("id", id)
}

@ApplicationScoped
class RegionRepository: PanacheRepository<Region> {
    fun findByName(name: String) = find("name", name).firstResult<Region>()
    fun deleteInstance(id: Long) = delete("id", id)
}

@ApplicationScoped
class SubnetRepository: PanacheRepository<Subnet> {
    fun findByName(name: String) = find("name", name).firstResult<Subnet>()
    fun deleteInstance(id: Long) = delete("id", id)
}

@ApplicationScoped
class VPCRepository: PanacheRepository<VPC> {
    fun findByName(name: String) = find("name", name).firstResult<VPC>()
    fun deleteInstance(id: Long) = delete("id", id)
}


Service Class

Kotlin
 
fun listAllEC2Instances(): Uni<List<EC2>> =  ec2Instance.listAll()

    fun listAllAZs(): Uni<List<Azone>> = azRepository.listAll()

    fun listAllRegions(): Uni<List<Region>> = regionRepository.listAll()

    fun listAllSubnets(): Uni<List<Subnet>> = subnetRepository.listAll()

    fun listAllVpcs(): Uni<List<VPC>> = vpcRepository.listAll()

    @Transactional
    fun saveEC2Insance(newEC2: EC2, subnetId: Long):Uni<EC2> {

        return subnetRepository.findById(subnetId)
            .onItem().ifNull().failWith(IllegalArgumentException("Invalid subnet id"))
            .onItem().transformToUni { subnet -> newEC2.subnet = subnet; Uni.createFrom().item(newEC2) }
            .onItem().transformToUni { it -> ec2Instance.persistAndFlush(it) }
            .onItem().invoke { it ->
                LoggerFactory.getLogger(javaClass).info("EC2 instance with id ${it.id} created")
            }

    }

    @Transactional
    fun deleteEC2Instance(id: Long): Uni<Boolean> {

        return ec2Instance.deleteById(id)
            .onItem().invoke { it ->
                LoggerFactory.getLogger(javaClass).info("EC2 instance with id $id deleted")
            }
            .onItem().transform { true }
    }


Resource Class

Kotlin
 
@GraphQLApi
@ApplicationScoped
class ClusterResource {

    @Inject
    lateinit var clusterService: ClusterService

    @Query("listAllEC2s")
    fun listAllEC2Instances(): Uni<List<EC2>>  = clusterService.listAllEC2Instances()

    @Query("listAllAZs")
    fun listAllAZs(): Uni<List<Azone>> = clusterService.listAllAZs()

    @Query("listAllRegions")
    fun listAllRegions(): Uni<List<Region>> = clusterService.listAllRegions()

    @Query("listAllSubnets")
    fun listAllSubnets(): Uni<List<Subnet>> = clusterService.listAllSubnets()

    @Query("listAllVPCs")
    fun listAllVPCs(): Uni<List<VPC>> = clusterService.listAllVpcs()

    @Mutation("addEC2Instance")
    fun addEC2Instance(ec2: EC2, subnetId: Long): Uni<EC2> = clusterService.saveEC2Insance(ec2, subnetId)

    @Mutation("deleteEC2Instance")
    fun deleteEC2Instance(instanceId: Long): Uni<Boolean> = clusterService.deleteEC2Instance(instanceId)
 }


Finally

You can Run the App and access this URL.

GraphQL UI

The GraphQL user interface provides a range of convenient pre-built functionalities, including a command history feature, the ability to list available operations, and an autocomplete feature, among others.

Summary

In this article, we have explored one of the solutions approaches for building Reactive and Native applications, acknowledging that each solution has its own trade-offs and benefits, and we must choose based on our priorities. We have highlighted the high performance and cloud-native support offered by Quarkus and suggested further exploration of these features. Additionally, we have discussed how GraphQL complements this solution by providing many ready-to-use features that make development faster and support low-code, no-code, and open API features. Finally, we have mentioned Kotlin as another excellent technology that offers null safety and eliminates boilerplate code.

The source code can be found on my GitHub. Also, you can reach out to me on LinkedIn for any questions or suggestions.

That’s all for now. Happy Learning!

Database GraphQL Quarkus Kotlin (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Efficient Data Management With Offset and Cursor-Based Pagination in Modern Applications
  • New ORM Framework for Kotlin
  • Pessimistic and Optimistic Locking With MySQL, jOOQ, and Kotlin
  • The Generic Way To Convert Between Java and PostgreSQL Enums

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!