Docs Menu
Docs Home
/ /

Tutorial: Build a Quarkus Application with Panache and MongoDB

Panache is a Quarkus framework-specific library that simplifies the development of Hibernate-based persistence layers. It reduces boilerplate code by providing built-in CRUD operations and type-safe queries.

Panache supports both the Active Record pattern, which embeds database operations directly in entity classes, and the Repository pattern, which separates data access logic into dedicated repository classes. It integrates with Quarkus to provide fast startup times and a low memory footprint. Panache works with Hibernate Object-Relational Mapping (ORM) and Java Persistence API (JPA) to simplify data access while keeping code clean.

In this tutorial, you build a Quarkus application with Panache to perform CRUD operations and aggregations on a MongoDB database. The application allows you to add, update, find, and delete books, as well as count books by genre.

In this tutorial, you perform the following actions:

  • Verify the prerequisites

  • Set up the project

  • Create the data model

  • Create REST API endpoints

  • Test the API

1

Before you begin, ensure you have the following:

  • A MongoDB Atlas account with a configured cluster. To learn how to set up an Atlas cluster, see the MongoDB Get Started guide.

  • Java version 21 or later. To learn more about installing Java, see the Oracle website.

  • Your preferred IDE.

  • Maven to manage project dependencies.

2

Create a folder to hold your Quarkus project. Navigate into this directory and create a Quarkus project with Maven by running the following command:

mvn io.quarkus:quarkus-maven-plugin:create \
-DprojectGroupId=io.quarkus.platform \
-DprojectArtifactId=quarkus-bom \
-DclassName="com.example.BookResource" \
-Dpath="/books"

Add the following dependencies to your pom.xml file:

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
<version>3.16.2</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mongodb-panache</artifactId>
</dependency>
</dependencies>

Build the application and download the dependencies by running the following command in your project directory:

mvn clean install
3

First, from the root directory of your project, navigate to src/main/java/com/<package>. Create a Book.java file in this directory . Inside this file, define the Book class as shown in the following code:

import io.quarkus.mongodb.panache.PanacheMongoEntity;
import io.quarkus.mongodb.panache.common.MongoEntity;
@MongoEntity(collection = "books")
public class Book extends PanacheMongoEntity {
public String title;
public String author;
public String genre;
public int year;
public Book() {
}
}

This class represents a book document in the MongoDB collection with fields for the title, author, genre, and year.

4

Create a BookRepository.java file in your package directory. Inside this file, define the BookRepository class as shown in the following code:

import com.quarkusWithPanache.model.Book;
import io.quarkus.mongodb.panache.PanacheMongoRepository;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class BookRepository implements PanacheMongoRepository<Book> {
}

Next, create a BookResource.java file in your package directory. Inside this file, define a resource class that uses the BookRepository interface you created in the preceding example, as shown in the following code:

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.quarkusWithPanache.model.Book;
import com.quarkusWithPanache.repository.BookRepository;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
import org.bson.Document;
import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.List;
@Path("/books")
public class BookResource {
@Inject
BookRepository bookRepository;
@Inject
MongoClient mongoClient;
private MongoCollection<Document> getCollection() {
return mongoClient.getDatabase("test").getCollection("books");
}
@Inject
public BookResource(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
// Define API endpoints here
}

The following sections show how to implement various API endpoints for CRUD operations and aggregations. You can add the code for each endpoint below the highlighted line in the preceding example.

You can insert a single book by adding the following code to your resource class:

@Inject
BookRepository bookRepository;
@POST
public Response addBook(Book book) {
bookRepository.persist(book);
return Response.status(Response.Status.CREATED).entity(book).build();
}

You can insert multiple books at once by adding the following code to your resource class:

@POST
@Path("/bulk")
public Response bulkAddBooks(List<Book> books) {
// Prepare documents for bulk write
List<Document> documents = new ArrayList<>();
for (Book book : books) {
documents.add(new Document("title", book.title)
.append("author", book.author)
.append("genre", book.genre)
.append("year", book.year));
}
getCollection().insertMany(documents);
return Response.status(Response.Status.CREATED).entity(books).build();
}

The getCollection method returns the database and collection name from the com.mongodb.client.MongoCollection package.

You can retrieve all books by adding the following code to your resource class:

@GET
public List<Book> getAllBooks() {
return bookRepository.listAll();
}

You can retrieve a specific book by its _id value by adding the following code to your resource class:

@GET
@Path("/{id}")
public Book getBookById(@PathParam("id") String id) {
return bookRepository.findById(new ObjectId(id));
}

You can delete a book by its _id value by adding the following code to your resource class:

@DELETE
@Path("/{id}")
public Response deleteBook(@PathParam("id") String id) {
boolean deleted = bookRepository.deleteById(new ObjectId(id));
return deleted ? Response.noContent().build() : Response.status(Response.Status.NOT_FOUND).build();
}

You can update a book by its _id value by adding the following code to your resource class:

@PUT
@Path("/{id}")
public Response updateBook(@PathParam("id") String id, Book book) {
Book entity = bookRepository.findById(new ObjectId(id));
if (entity == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
entity.title = book.title;
entity.author = book.author;
entity.genre = book.genre;
entity.year = book.year;
bookRepository.update(entity);
return Response.ok(entity).build();
}

You can count books by genre by adding the following aggregation code to your resource class:

@GET
@Path("/aggregate/genre-count")
public Response countBooksByGenre() {
List<Document> pipeline = new ArrayList<>();
pipeline.add(new Document("$group", new Document("_id", "$genre")
.append("count", new Document("$sum", 1))));
List<Document> result = getCollection()
.aggregate(pipeline)
.into(new ArrayList<>());
return Response.ok(result).build();
}
5

Start your application on http://localhost:8080 by running the following command from the root directory of your project:

mvn spring-boot:run

You can test the API endpoints by running the following curl commands:

The following curl command shows how to insert a single book:

curl -X POST "http://localhost:8080/books" -H "Content-Type: application/json" -d '{
"title": "Quarkus in Action",
"author": "John Doe",
"genre": "Programming",
"year": 2023
}'

The following curl command shows how to insert multiple books:

curl -X POST http://localhost:8080/books/bulk \
-H "Content-Type: application/json" \
-d '[
{
"title": "The Midnight Library",
"author": "Matt Haig",
"genre": "Fiction",
"year": 2020
},
{
"title": "Sapiens: A Brief History of Humankind",
"author": "Yuval Noah Harari",
"genre": "Non-Fiction",
"year": 2011
}
]'

The following curl command shows how to retrieve all books:

curl -X GET "http://localhost:8080/books" | jq

The following curl command shows how to retrieve a specific book:

curl -X GET "http://localhost:8080/books/672f873b421eaa0c3e4da49f" | jq

The following curl command shows how to delete a book:

curl -X DELETE "http://localhost:8080/books/673f81b65750de0757a4bbfb" | jq

The following curl command shows how to update a book:

curl -X PUT "http://localhost:8080/books/672f856f421eaa0c3e4da49e" \
-H "Content-Type: application/json" \
-d '{
"title": "Quarkus in Action",
"author": "John Doe",
"genre": "Programming",
"year": 2021
}'

The following curl command shows how to count books by genre:

curl -X GET "http://localhost:8080/books/aggregate/genre-count" | jq

Tip

Using jq to format JSON output

Use the jq tool, as shown in the preceding examples, to format the JSON output from the API for better readability. You can install jq by following the instructions on the jq website.

To view the complete version of the example in this tutorial, see the quarkus-panache-with-mongodb Github repository.

To learn more about Panache, see the MongoDB with Panache documentation on the Quarkus website.

Back

Spring Data MongoDB

On this page