Overview
In this guide, you can learn how to create a Java REST API that uses Quarkus as the web framework and Eclipse JNoSQL to access MongoDB. Quarkus is an open-source Java framework designed for cloud-native microservices and serverless development. Eclipse JNOSQL implements the Jakarta NoSQL and Jakarta Data specifications to simplify the integration of Java applications with NoSQL databases.
The application in this tutorial consists of the following layers:
Database layer: MongoDB provides data storage and retrieval.
Application layer: Quarkus handles HTTP requests, routing, and dependency injection.
Data access layer: JNoSQL provides MongoDB document mapping and repository patterns.
Why Use MongoDB with Quarkus?
This tutorial uses the Quarkus JNoSQL Extension to access MongoDB, which provides a unified API for NoSQL databases and allows you to work with MongoDB by using familiar Java patterns and annotations. As a result, you can use MongoDB and Quarkus to develop lightweight applications with minimal configuration.
By integrating MongoDB with Quarkus, you can leverage Quarkus' fast startup times and efficient resource use alongside MongoDB's flexible document model. This combination supports applications that require type safety, scalability, and rapid development cycles. You can use MongoDB and Quarkus to create real world applications such as microservices, cloud-native APIs, or systems that require high performance and low resource consumption.
Quick Start Tutorial
This tutorial shows you how to build a REST API that uses MongoDB and Quarkus. The application accesses sample restaurant data, queries the data, and returns the results through RESTful endpoints. The tutorial also includes instructions for connecting to a MongoDB cluster hosted on MongoDB Atlas.
Tip
If you prefer to connect to MongoDB by using the Java driver without Quarkus, see the Get Started with the Java Driver tutorial.
Set Up Your Project
Follow the steps in this section to install the project dependencies, create an Atlas cluster, and set up the application structure.
Verify the prerequisites.
To create the Quick Start application, install the following software in your development environment:
Prerequisite | Notes |
|---|---|
Install JDK version 21 or later. | |
Use version 3.8.1 or later. | |
This command-line interface allows you to create and manage Quarkus
projects from your terminal. Important: This tutorial uses version 3.30.6, and later versions
might cause errors. Follow the installation instructions
corresponding to your operating system to install the specific version. | |
Code editor | Use the code editor of your choice. |
Terminal app and shell | For MacOS users, use Terminal or a similar app. For Windows users, use PowerShell or Command Prompt. |
Create a MongoDB Atlas cluster.
MongoDB Atlas is a fully managed cloud database service that hosts your
MongoDB deployments. If you do not have a MongoDB deployment, you can create a MongoDB
cluster for free by completing the
MongoDB Get Started
tutorial. The MongoDB Get Started tutorial also demonstrates how to load sample
datasets into your cluster, including the sample_restaurants database
that is used in this tutorial.
To connect to your MongoDB cluster, you must use a connection string. To learn how to retrieve your connection string, see the Add your connection string section of the MongoDB Get Started tutorial.
Important
Save your connection string in a secure location.
Create your Quarkus project.
From your terminal, run the following command to create a new Quarkus project
named quarkus-quickstart that configures the Quarkus JNoSQL Extension for
MongoDB and JSON serialization for REST endpoints:
quarkus create app quarkus-quickstart --extensions=jnosql-mongodb,resteasy-jackson
Then, navigate to your project directory by running the following command:
cd quarkus-quickstart
Configure your database connection.
Navigate to the src/main/resources/application.properties file and add
the following configuration properties:
jnosql.document.database=sample_restaurants quarkus.mongodb.connection-string=<connection string>
This code configures your connection to the sample_restaurants database in your
MongoDB cluster. Replace the <connection string> placeholder with the connection string
that you saved in a previous step.
Clean up template files.
The Quarkus project template includes some sample files that you can remove
for this tutorial. To delete these unneeded files, select the tab
corresponding to your operating system and run the following commands from
your quarkus-quickstart directory:
rm src/main/java/org/acme/Car.java rm src/main/java/org/acme/Garage.java rm src/test/java/org/acme/GarageTest.java rm src/main/java/org/acme/GreetingResource.java rm src/test/java/org/acme/GreetingResourceIT.java rm src/test/java/org/acme/GreetingResourceTest.java
del src/main/java/org/acme/Car.java del src/main/java/org/acme/Garage.java del src/test/java/org/acme/GarageTest.java del src/main/java/org/acme/GreetingResource.java del src/test/java/org/acme/GreetingResourceIT.java del src/test/java/org/acme/GreetingResourceTest.java
Create Your Application
After setting up the project structure and dependencies, follow the steps in this section to create your data model, repository class, and REST endpoints.
Create the Restaurant model.
Create a file named Restaurant.java in the src/main/java/org/acme directory
and paste the following code:
package org.acme; import jakarta.nosql.Column; import jakarta.nosql.Entity; import jakarta.nosql.Id; /** * Represents a restaurant entity from the sample_restaurants database . * This class is used as an entity in the MongoDB database. */ public class Restaurant { private String id; private String name; private String borough; private String cuisine; // Default constructor required by JNoSQL public Restaurant() {} // Constructor public Restaurant(String id, String name, String borough,String cuisine) { this.id = id; this.name = name; this.borough = borough; this.cuisine = cuisine; } // Getters and setters public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getBorough() { return borough; } public void setBorough(String borough) { this.borough = borough; } public String getCuisine() { return cuisine; } public void setCuisine(String cuisine) { this.cuisine = cuisine; } }
This file defines the Restaurant entity class, which maps to documents
in the sample_restaurants.restaurants collection. The @Entity annotation marks this
class as a JNoSQL entity, and the field annotations map Java properties to
document fields.
Create the repository class.
Create a file named RestaurantRepository.java in the src/main/java/org/acme
directory and paste the following code:
package org.acme; import jakarta.data.repository.Repository; import org.eclipse.jnosql.mapping.NoSQLRepository; import java.util.List; /** * Interface for managing restaurant data. * * It uses the Jakarta Data Specification capabilities. * */ public interface RestaurantRepository extends NoSQLRepository<Restaurant, String> { List<Restaurant> findByBorough(String borough); List<Restaurant> findByCuisine(String cuisine); }
This repository class provides methods for accessing restaurant data in MongoDB.
It defines custom findByBorough() and findByCuisine() query methods, and
you can also use a RestaurantRepository instance to access built-in create,
read, update, and delete methods.
Create the REST resource class.
In the src/main/java/org/acme directory, create a file named
RestaurantResource.java and paste the following code:
package org.acme; import jakarta.inject.Inject; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.util.List; /** * REST API controller for restaurant operations. * Provides endpoints for retrieving restaurant data from MongoDB. */ public class RestaurantResource { RestaurantRepository restaurantRepository; /** * Retrieves all restaurants from the database. * * @return List of all restaurants */ public Response getAllRestaurants() { try { List<Restaurant> restaurants = restaurantRepository.findAll().toList(); System.out.println("Found " + restaurants.size() + " restaurants"); return Response.ok(restaurants).build(); } catch (Exception e) { e.printStackTrace(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Error retrieving restaurants: " + e.getMessage()) .build(); } } /** * Retrieves filtered restaurants in Queens that contain "Moon" in the name. * * @return List of filtered restaurants */ public Response getFilteredRestaurants() { try { // Temporarily use findAll() to test basic connectivity List<Restaurant> allRestaurants = restaurantRepository.findAll().toList(); System.out.println("Total restaurants found: " + allRestaurants.size()); // Filter for Queens restaurants that also have "Moon" in the name List<Restaurant> queensRestaurants = allRestaurants.stream() .filter(restaurant -> "Queens".equals(restaurant.getBorough()) && restaurant.getName() != null && restaurant.getName().toLowerCase().contains("moon")) .toList(); System.out.println("Queens restaurants found: " + queensRestaurants.size()); return Response.ok(queensRestaurants).build(); } catch (Exception e) { e.printStackTrace(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Error retrieving filtered restaurants: " + e.getMessage()) .build(); } } /** * Retrieves restaurants by cuisine type. * * @param cuisine The cuisine type to filter for * @return List of restaurants that have the specified cuisine */ public Response getRestaurantsByCuisine( String cuisine) { try { List<Restaurant> restaurants = restaurantRepository.findByCuisine(cuisine); return Response.ok(restaurants).build(); } catch (Exception e) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Error retrieving restaurants by cuisine: " + e.getMessage()) .build(); } } }
This REST resource class defines the following HTTP endpoints:
GET /restaurants/: Retrieves all documents from therestaurantscollectionGET /restaurants/browse: Retrieves documents that represent restaurants in Queens containing"Moon"in their name, performing a case-insenstive queryGET /restaurants/cuisine/{cuisine}: Retrieves documents that represent restaurants offering the specifiedcuisinevalue
Create a test class.
In the src/test/java/org/acme directory, create a file named RestaurantRepositoryTest.java
and paste the following code:
package org.acme; import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; /** * RestaurantRepositoryTest is a test class for testing the RestaurantRepository operations. * * It uses the Quarkus Test framework to test the restaurant data access. */ public class RestaurantRepositoryTest { RestaurantRepository restaurantRepository; public void testRetrieveRestaurants() { // Test repository injection and MongoDB connection assertThat(restaurantRepository).isNotNull(); } public void testFindRestaurantsByBorough() { // Test that the method exists and returns data List<Restaurant> restaurants = restaurantRepository.findByBorough("Queens"); assertThat(restaurants).isNotNull(); } }
This file uses Quarkus's testing framework for integration testing. The code defines the following methods to test your MongoDB connection:
testRetrieveRestaurants(): Verifies that yourRestaurantRepositoryclass accesses MongoDBtestFindRestaurantsByBorough(): Verifies that thefindByBorough()method retrieves MongoDB data
Run Your Application
Finally, follow the steps in this section to run your REST API and
test the endpoints by using curl commands.
Run the tests.
First, run the following command from your project directory to run the test suite:
./mvnw test
This command runs the RestaurantRepositoryTest class and verifies
that your application can access MongoDB data. If successful, your command output
contains the following information:
[INFO] Results: [INFO] [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: ... s [INFO] Finished at: ... [INFO] ------------------------------------------------------------------------
Manually test the REST endpoints.
In a separate terminal window, run the following curl commands
to test the REST endpoints. Each endpoint returns JSON data containing
restaurant information from the sample_restaurants.restaurants collection.
If successful, your commands return data similar to the sample outputs.
Retrieve all restaurants.
curl http://localhost:8080/restaurants/ [{"id":"...","name":"Morris Park Bake Shop","borough":"Bronx","cuisine":"Bakery"}, {"id":"...","name":"Wilken'S Fine Food","borough":"Brooklyn","cuisine":"Delicatessen"}, {"id":"...","name":"Taste The Tropics Ice Cream","borough":"Brooklyn","cuisine":"Ice Cream, Gelato, Yogurt, Ices"}, {"id":"...","name":"Carvel Ice Cream","borough":"Queens","cuisine":"Ice Cream, Gelato, Yogurt, Ices"}, ...] Retrieve restaurants in Queens that have
"Moon"in the name.curl http://localhost:8080/restaurants/browse [{"id":"...","name":"Somoon","borough":"Queens","cuisine":"Asian"}, {"id":"...","name":"New Moon Star Restaurant","borough":"Queens","cuisine":"Chinese"}, {"id":"...","name":"Moon Tikka Grill","borough":"Queens","cuisine":"Indian"}, {"id":"...","name":"Silver Moon Diner","borough":"Queens","cuisine":"American"}, {"id":"...","name":"Mooney'S Public House","borough":"Queens","cuisine":"Irish"}, {"id":"...","name":"Moon Light Crill Rest.","borough":"Queens","cuisine":"Indian"}, {"id":"...","name":"Full Moon Cafe","borough":"Queens","cuisine":"Café/Coffee/Tea"}, {"id":"...","name":"Pacific Moon","borough":"Queens","cuisine":"Chinese"}, {"id":"...","name":"Moon Palace Kitchen","borough":"Queens","cuisine":"Chinese"}, {"id":"...","name":"Honey Moon Coffee Shop 1766096115682","borough":"Queens","cuisine":"Café/Coffee/Tea"}, {"id":"...","name":"Honey Moon Coffee Shop","borough":"Queens","cuisine":"Café/Coffee/Tea"}] Retrieve restaurants by cuisine type.
The following command queries for restaurants that have a
cuisinevalue of"Czech", but you can replace this parameter with any cuisine:curl http://localhost:8080/restaurants/cuisine/Czech [{"id":"...","name":"Koliba Restaurant","borough":"Queens","cuisine":"Czech"}, {"id":"...","name":"Milan'S Restaurant","borough":"Brooklyn","cuisine":"Czech"}, {"id":"...","name":"Bohemian Beer Garden","borough":"Queens","cuisine":"Czech"}, {"id":"...","name":"Hospoda","borough":"Manhattan","cuisine":"Czech"}, {"id":"...","name":"Olde Prague Tavern","borough":"Queens","cuisine":"Czech"}, {"id":"...","name":"Brooklyn Beet Company","borough":"Brooklyn","cuisine":"Czech"}]
Congratulations on completing the Quarkus Quick Start tutorial! After you complete
these steps, you have a Java Quarkus REST API that connects to your MongoDB
deployment, runs queries on sample restaurant data, and exposes the results
through HTTP endpoints that you can test by using curl commands.
Additional Resources
To learn more about Quarkus, JNoSQL, and MongoDB, see the following resources:
Quarkus documentation
Eclipse JNoSQL documentation
MongoDB Java Driver documentation