A Practical Guide to Quarkus for Beginners: 7 Key Solutions for a Successful Start

introduction

In response to growing demand in the world of application development, Quarkus has emerged as a leading force that redefines expectations.

In this blog, we will explore and accompany you on how to approach Quarkus for the first time, a development framework/Framework that has become the favorite choice of developers and companies looking for efficient and high-performance Java solutions.

I want to share with you key solutions for the needs that you will surely encounter when you want to get started in this technology. We'll review how to build a quick application, integrate a database into it, use a great tool for manipulating dependencies, error handling, and more.

I'm Pablo, Software Engineer at Kranio, and I invite you to join me in this challenge! 👋

Before starting with the most valuable tricks, we must start by understanding and using the Quarkus platform to build our first application.

Go to this link: https://quarkus.io/

Prerequisites:

  • Java 11 or +
  • IDE of your choice (recommendation: IntelliJ)
  • (Make sure you have your environment variables properly configured at the system level)

Quarkus platform It's an incredible tool, it allows us to select versions, compilation tools and dependencies in a very intuitive way, and then with a single click download a complete structure and build it with these simple commands:

  • Maven: . /mvnw quarkus:dev
  • Gradlew: . /gradlew QuarkusDev

If you see this on your console, your app is ready!

Now let's get to the important thing, imagine that you need to integrate a database to start exploring or developing directly.

Well, H2 is the way.

1. Integrating a database to Quarkus in record time

H2 is an open source relational database management system (RDBMS) written in Java. It's known for being lightweight, fast, and easy to use, and is a popular choice for developing and testing Java applications.

When we want to integrate a db like H2, we first have to add the corresponding library, Panache.

These are the 2 dependencies you'll need:


./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-hibernate-orm-panache"

./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-jdbc-h2"


It is important to also configure the database in the file application.properties

In this example, the application is communicating with the database. When you see that data is being stored. If you want to see an example of this project, check out this repository: Restart Piquark USH2

2. Add dependencies to the current project without the risk of impacting or downloading the application.

Imagine that in the previous point, where we integrated H2, the situation was different. Instead of working on a Quickstart that doesn't yet have logic or other dependencies, you work with a robust application with several dependencies, and you have the need to add one more without downloading the application, to ensure that everything continues to work properly and to save valuable time in the process.

Well, for this situation there is a tool called MicroProfile. Let me briefly explain:

MicroProfile is a Java specification intended to simplify and standardize the development of applications based on MicroServices in the context of the Java Enterprise Edition (Java EE) platform. For your convenience, Quarkus is integrated by default, so you can use it in different ways, let's review one.

MicroProfile can do much more, you can read more about that here: https://microprofile.io/https://microprofile.io/

In the developer console we have a Menu. In it, several options. By placing the letter “h” we will access an even more extensive menu.

If we enter the letter “d” it will take us to a page in the browser where we can modify all the extensions and settings of the application.

If we position ourselves above it, an icon will appear where it takes us to the guide for each one. Here we have a list of the extensions we are using.

We can also change any configuration of our application. Without leaving or closing the application

3. You need to view http responses in a controlled manner

When we want to do error handling in Quarkus, we can do this in a variety of ways, since the framework provides mechanisms for handling exceptions and customizing behavior in unexpected situations.

Review this code:



@GET
@Path("/maxima")
@Produces(MediaType.TEXT_PLAIN)
public String maxima(){
return Integer.toString(temperatures.maxima());


When we leave it as a String and it has no parameters it throws us an error.

In this case, what happens is not the right way to work with REST API, this error, although it reveals what is happening, is not useful for the person/service that will consume the API.

That's why I'll show you a better way:


@GET
@Path("/maxima")
@Produces(MediaType.TEXT_PLAIN)
public Response maxima(){
			if (temperatures.isEmpty()){
					return Response.status(404). entity( o: "no hay teperaturas"). build();
		  }else {
					int temperatureMaxima = temperatures.maxima();
					return Response.ok(Integer.toString (temperatureMaxima)) .build();
			}
}


It's important that you know how to choose the right HTTP code for each case. And that, if possible, you return a standard structure with the error message.

4. How to decouple business logic from the HTTP controller

To decouple the business logic from the controller, you'll use dependency injection, so let's review the pattern Service Object.

The thing is that with this injection, you will be automatically instantiating that service in the controller. The annotation @ApplicationScoped is needed in the classroom.


@ApplicationScoped
public class GenreRepository implements PanacheRepository {
}


Then you must create a variable of this class Genre Repository and we indicate Quarkus to inject it (which means that it supplies it automatically) using @Inject. You can then use this variable in your code.



public class GenreResource {
    @Inject
    public GenreRepository genreRepository;

Important: If we make a small modification, such as changing the visibility of this variable to private, we could have performance problems and receive warnings from Quarkus. Therefore, I suggest that you keep the visibility as private, but at the package level.

5. You have a query that answers too much data, it's time to use pagination

It's common in life as a developer to face databases with thousands of data, and when we want to return them we realize that there are so many that it becomes confusing and messy.

PanacheQuery it will allow you to take care of the query you want to send to the database, taking advantage of the power of Hibernate ORM (which is what it has underneath).

Let's review how to apply pagination to a query in order to provide fewer results per endpoint and thus not subject the database to so much stress.

In the following example you are going to implement a method FindPage In the classroom Genre Repository What does it use Panache to paginate the results.


@ApplicationScoped
public class GenreRepository implements PanacheRepository {
    public PanacheQuery findPage(int page) {
        Page p = new Page(page - 1, 5);                                                         //aqui definimos la cantidad de objetos q estaran en cada pagina repository tambien lo podemos ocupar como servicio
        var query = findAll(Sort.descending("id"));
        query.page(p);
        return query;
    }
}


In this case, the page has 5 units.

Also in PanacheQuery, the class TedResponse pages is used to encapsulate information about pagination such as the current page, the current page total.


public record PaginatedResponse"E"(int page, int totalPages, List"E" data) {
    public PaginatedResponse(PanacheQuery"E" query){
        this(query.page().index + 1, query.pageCount(),query.list());
    }
}

@QueryParam (“page”) @DefaultValue (“1") int page: This is a method parameter that is associated with the page query parameter in the URL. If not provided, it will default to 1. The rest of the code is from a filtered search with the name of the genre to bring it paginated.


@GET
public PaginatedResponse"Genre" list(
			@QueryParam("page")@DefaultValue("1")intpage,
			@QueryParam("q") String q) {
	var query = genres. findPage (page) ;
	¡f (a != null) {
			var nameLike = "%" + q + "%";
			query.filter ( filterName: "name.like", Parameters.with( name: "name", nameLike));
	}
	return new PaginatedResponse"" (query);
}


6. Having trouble managing response formats from your endpoints?

Annotations are powerful tools, so here's a little bit of their potential

Jackson annotation:

With the extension Jackson can we just forget about converting things to JSON. Jackson knows how to inspect the types of data that our methods return and convert them to JSON if we tell them to. In this way, you can easily create specific entities that correspond to models and return them as a result of our endpoints, to let them reach the consumer of our API as if they were objects JSON normal.

If we want to modify the way in which we serialize JSON an entity, we have the annotations @JsonIgnore, @UpdateTimestamp, @JsonProperty (“”), @JsonAlias ({” gN”, “n”}) to influence the way in which Jackson serializes our entity, to hide fields or rename them.

  • @CreationTimestamp. It will be automatically filled with the current date and time.
  • @JsonIgnore. This will ignore this information and will not show it in the Json response.
  • @UpdateTimestamp. To keep track of when the last update was made to the entity.
  • @JsonProperty (“Name”). If we want to change the name property in Json.
  • @JsonAlias ({” geneName”, “name”}). TIt allows you to adapt your code to handle these changes without having to modify the internal structure of your class.

7. Do you want to prevent an empty piece of data from coming into the body?

One of the most common situations I face when making APIs is maintaining proper data validation. For these cases, the extension is useful Hibernate Validator (Quarkus.io).

To add it, run the following command at the end of the project.



./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-hibernate-validator"

You can now add a JSON annotation:

  • @NotBlank The string must contain at least one character other than white space.
  • @NotNull This field or parameter cannot have a null value.
  • @Email Field must contain a string that is recognized as a valid email address.
  • @Pattern (regexp = “[a-zA-z] +”) Define restrictions based on regular expressions.
  • @Size (min = 2, max = 50) Defines restrictions on the size of the string.
  • @Min and @Max: Set minimum and maximum limits for numerical values.

For more annotations, check this out: https://www.baeldung.com/jackson-annotations

Conclusion

With all this information you are ready to face without fear of developing in Quarkus, I have given you some of my best tricks! If you still feel like you need our help, we'll be happy to support you!

Ready to take your Quarkus skills to the next level?

At Kranio, we have experts in developing Java applications who will help you implement efficient solutions using Quarkus, ensuring the scalability and performance of your projects. Contact us and discover how we can promote the digital transformation of your company.

Pablo Trujillo

September 16, 2024