Building RESTful Microservices in Java with Quarkus and RESTEasy
Microservices have become a popular architectural style for building scalable, maintainable, and flexible systems. One of the most crucial components in microservices architecture is the way services communicate with each other. Typically, this is done using REST APIs (Representational State Transfer), a specification that defines how to interact over HTTP.
In this blog, we will explore how RESTful web services allow microservices to communicate with each other, using Quarkus and its RESTEasy extension, which provides support for building RESTful services with Java’s JAX-RS API. We will also walk through the development of a sample application where we create a simple student management system using Quarkus.
What is REST API?
A REST API (or RESTful web service) is a standard that defines how two services interact over HTTP. REST provides a set of operations (such as GET, POST, PUT, and DELETE) that enable the interaction between a consumer (client) and a producer (service). The interaction often happens in the form of HTTP requests where:
- Consumer: Sends an HTTP request.
- Producer: Receives the request and returns data, usually in JSON format.
In microservices, REST APIs act as the communication layer, allowing the services to exchange information in a structured way.
Components of a Microservice
To be considered a microservice, the service must have three key components:
- Functionality (Business Logic): This is the core logic the service performs.
- API: An interface that allows other services or clients to interact with the service.
- Database: Each microservice typically has its own database for data storage, ensuring that the services are loosely coupled.
JAX-RS and RESTEasy in Quarkus
Java provides an API called JAX-RS (Java API for RESTful Web Services), which simplifies the development of RESTful applications. It includes several key annotations that allow developers to define REST endpoints quickly.
With Quarkus, you get the RESTEasy extension, which implements JAX-RS, and allows you to build RESTful services efficiently. Additionally, Quarkus provides the resteasy-jsonb extension, which makes handling JSON data simple.
Key JAX-RS Annotations
Here are some of the key annotations that JAX-RS provides:
- @Path: Defines the URI path to access the service or method.
- @GET: Specifies that the method will handle HTTP GET requests.
- @POST: Handles HTTP POST requests.
- @PUT: Handles HTTP PUT requests.
- @DELETE: Handles HTTP DELETE requests.
- @Produces: Specifies the media type (e.g., JSON, plain text) the method will produce in the HTTP response.
- @PathParam: Extracts path parameters from the URL for dynamic input.
Creating a Quarkus Application with RESTEasy
Let’s create a Quarkus project to demonstrate how to build REST APIs using RESTEasy.
Step 1: Creating the Project
Run the following command to create a Quarkus project with the RESTEasy and resteasy-jsonb extensions:
mvn io.quarkus:quarkus-maven-plugin:create \
-DprojectGroupId=com.harsh.tech \
-DprojectArtifactId=student \
-DclassName=com.harsh.tech.Student \
-Dextensions=resteasy-jsonb
This will generate a basic Quarkus project with the necessary dependencies and extensions to build RESTful web services.
Step 2: Writing the Student Class
Now, we’ll create a Student
class that models the data for each student, including properties like id
, name
, phone
, and course
.
package com.harsh.tech;
public class Student {
public int id;
public String name;
public int phone;
public String course;
// Constructor
public Student(int id, String name, int phone, String course) {
this.id = id;
this.name = name;
this.phone = phone;
this.course = course;
}
}
- Student class: This is a simple POJO (Plain Old Java Object) with fields for
id
,name
,phone
, andcourse
. - Constructor: Initializes a student object with values for each field
Step 3: Building REST Endpoints in MyStudent Class
Next, we’ll build the RESTful web services to manage students. The MyStudent
class defines a few endpoints for different actions like getting all students, counting the students, and searching for a student by ID.
package com.harsh.tech;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.Optional;
@Path("/main")
public class MyStudent {
// 1. Hello World Endpoint
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/hello")
public String hello() {
return "Hello RestEasy";
}
// 2. Get All Students Endpoint
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/all")
public List<Student> getAllStudents() {
return List.of(
new Student(1, "Harsh", 11111, "DevOps"),
new Student(2, "Rahul", 22222, "Machine Learning"),
new Student(3, "Ankit", 33333, "Artificial Intelligence"),
new Student(4, "Manan", 44444, "Python Programming")
);
}
// 3. Count Students Endpoint
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/count")
public int count() {
return getAllStudents().size();
}
// 4. Search Student by ID Endpoint
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/search/{x}")
public Optional<Student> getStudent(@PathParam("x") int id) {
return getAllStudents().stream()
.filter(student -> student.id == id)
.findFirst();
}
}
Step-by-Step Breakdown
- Hello World Endpoint:
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/hello")
public String hello() {
return "Hello RestEasy";
}
- The
@GET
annotation defines that this method will handle HTTP GET requests. - The
@Produces(MediaType.TEXT_PLAIN)
annotation specifies that the response will be plain text. - Access this endpoint at
http://localhost:8080/main/hello
to see the "Hello RestEasy" message.
2. Get All Students:
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/all")
public List<Student> getAllStudents() {
return List.of(
new Student(1, "Harsh", 11111, "DevOps"),
new Student(2, "Rahul", 22222, "Machine Learning"),
new Student(3, "Ankit", 33333, "Artificial Intelligence"),
new Student(4, "Manan", 44444, "Python Programming")
);
}
- This endpoint returns a list of students in JSON format using the
@Produces(MediaType.APPLICATION_JSON)
annotation. - Access this at
http://localhost:8080/main/all
to get all student details in JSON.
3. Count Students:
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/count")
public int count() {
return getAllStudents().size();
}
- This endpoint returns the count of all students.
- Access it at
http://localhost:8080/main/count
to get the number of students.
4. Search Student by ID:
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/search/{x}")
public Optional<Student> getStudent(@PathParam("x") int id) {
return getAllStudents().stream()
.filter(student -> student.id == id)
.findFirst();
}
- This endpoint allows searching for a specific student by their ID using the
@PathParam
annotation, which extracts the ID from the URL. - Access this at
http://localhost:8080/main/search/{x}
, where{x}
is the student ID.
Run the application using :
.\mvnw compile quarkus:dev
Conclusion
In this blog, we’ve explored how to build a simple REST API using Quarkus and RESTEasy in Java. We demonstrated key concepts like how services communicate using REST APIs, the role of JAX-RS, and how Quarkus simplifies RESTful web service development.
The project we created includes essential microservice components such as functionality, API, and JSON data exchange. By following this tutorial, you can now create your own RESTful microservices, build endpoints, and expose them to the network efficiently using Quarkus.
Now, it’s time to dive deeper into microservices, including how to manage data persistence and scale your services with Quarkus in the cloud!