Explore Developer Center's New Chatbot! MongoDB AI Chatbot can be accessed at the top of your navigation to answer all your MongoDB questions.

Join us at AWS re:Invent 2024! Learn how to use MongoDB for AI use cases.
MongoDB Developer
Java
plus
Sign in to follow topics
MongoDB Developer Centerchevron-right
Developer Topicschevron-right
Languageschevron-right
Javachevron-right

REST APIs with Java, Spring Boot, and MongoDB

Maxime Beugnet4 min read • Published Oct 25, 2023 • Updated Oct 25, 2023
SpringJava
FULL APPLICATION
Facebook Icontwitter iconlinkedin icon
Rate this code example
star-empty
star-empty
star-empty
star-empty
star-empty
social-githubView Code

GitHub repository

If you want to write REST APIs in Java at the speed of light, I have what you need. I wrote this template to get you started. I have tried to solve as many problems as possible in it.
So if you want to start writing REST APIs in Java, clone this project, and you will be up to speed in no time.
1git clone https://github.com/mongodb-developer/java-spring-boot-mongodb-starter
That’s all folks! All you need is in this repository. Below I will explain a few of the features and details about this template, but feel free to skip what is not necessary for your understanding.

README

All the extra information and commands you need to get this project going are in the README.md file which you can read in GitHub.

Spring and MongoDB configuration

The configuration can be found in the MongoDBConfiguration.java class.
1package com.mongodb.starter;
2
3import [...]
4
5import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
6import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;
7
8@Configuration
9public class MongoDBConfiguration {
10
11 @Value("${spring.data.mongodb.uri}")
12 private String connectionString;
13
14 @Bean
15 public MongoClient mongoClient() {
16 CodecRegistry pojoCodecRegistry = fromProviders(PojoCodecProvider.builder().automatic(true).build());
17 CodecRegistry codecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(), pojoCodecRegistry);
18 return MongoClients.create(MongoClientSettings.builder()
19 .applyConnectionString(new ConnectionString(connectionString))
20 .codecRegistry(codecRegistry)
21 .build());
22 }
23
24}
The important section here is the MongoDB configuration, of course. Firstly, you will notice the connection string is automatically retrieved from the application.properties file, and secondly, you will notice the configuration of the MongoClient bean.
A Codec is the interface that abstracts the processes of decoding a BSON value into a Java object and encoding a Java object into a BSON value.
A CodecRegistry contains a set of Codec instances that are accessed according to the Java classes that they encode from and decode to.
The MongoDB driver is capable of encoding and decoding BSON for us, so we do not have to take care of this anymore. All the configuration we need for this project to run is here and nowhere else.
You can read the driver documentation if you want to know more about this topic.

Multi-document ACID transactions

Just for the sake of it, I also used multi-document ACID transactions in a few methods where it could potentially make sense to use ACID transactions. You can check all the code in the MongoDBPersonRepository class.
Here is an example:
1private static final TransactionOptions txnOptions = TransactionOptions.builder()
2 .readPreference(ReadPreference.primary())
3 .readConcern(ReadConcern.MAJORITY)
4 .writeConcern(WriteConcern.MAJORITY)
5 .build();
6
7@Override
8public List<PersonEntity> saveAll(List<PersonEntity> personEntities) {
9 try (ClientSession clientSession = client.startSession()) {
10 return clientSession.withTransaction(() -> {
11 personEntities.forEach(p -> p.setId(new ObjectId()));
12 personCollection.insertMany(clientSession, personEntities);
13 return personEntities;
14 }, txnOptions);
15 }
16}
As you can see, I’m using an auto-closeable try-with-resources which will automatically close the client session at the end. This helps me to keep the code clean and simple.
Some of you may argue that it is actually too simple because transactions (and write operations, in general) can throw exceptions, and I’m not handling any of them here… You are absolutely right and this is an excellent transition to the next part of this article.

Exception management

Transactions in MongoDB can raise exceptions for various reasons, and I don’t want to go into the details too much here, but since MongoDB 3.6, any write operation that fails can be automatically retried once. And the transactions are no different. See the documentation for retryWrites.
If retryable writes are disabled or if a write operation fails twice, then MongoDB will send a MongoException (extends RuntimeException) which should be handled properly.
Luckily, Spring provides the annotation ExceptionHandler to help us do that. See the code in my controller PersonController. Of course, you will need to adapt and enhance this in your real project, but you have the main idea here.
1@ExceptionHandler(RuntimeException.class)
2public final ResponseEntity<Exception> handleAllExceptions(RuntimeException e) {
3 logger.error("Internal server error.", e);
4 return new ResponseEntity<>(e, HttpStatus.INTERNAL_SERVER_ERROR);
5}

Aggregation pipeline

MongoDB's aggregation pipeline is a very powerful and efficient way to run your complex queries as close as possible to your data for maximum efficiency. Using it can ease the computational load on your application.
Just to give you a small example, I implemented the /api/persons/averageAge route to show you how I can retrieve the average age of the persons in my collection.
1@Override
2public double getAverageAge() {
3 List<Bson> pipeline = List.of(group(new BsonNull(), avg("averageAge", "$age")), project(excludeId()));
4 return personCollection.aggregate(pipeline, AverageAgeDTO.class).first().averageAge();
5}
Also, you can note here that I’m using the personCollection which was initially instantiated like this:
1private MongoCollection<PersonEntity> personCollection;
2
3@PostConstruct
4void init() {
5 personCollection = client.getDatabase("test").getCollection("persons", PersonEntity.class);
6}
Normally, my personCollection should encode and decode PersonEntity object only, but you can overwrite the type of object your collection is manipulating to return something different — in my case, AverageAgeDTO.class as I’m not expecting a PersonEntity class here but a POJO that contains only the average age of my "persons".

Swagger

Swagger is the tool you need to document your REST APIs. You have nothing to do — the configuration is completely automated. Just run the server and navigate to http://localhost:8080/swagger-ui.html. the interface will be waiting for you.
The Swagger UI
You can test the REST APIs from this web page and explore the models. Don’t forget to disable it in production. ;-)
That's all I did to make it work:
1<dependency>
2 <groupId>org.springdoc</groupId>
3 <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
4 <version>2.2.0</version>
5</dependency>
See the documentation for more information.

Nyan Cat

Yes, there is a Nyan Cat section in this post. Nyan Cat is love, and you need some Nyan Cat in your projects. :-)
Did you know that you can replace the Spring Boot logo in the logs with pretty much anything you want?
Nyan Cat
Well, now you know. You are welcome.
Have a look at the banner.txt file if you want to replace this awesome Nyan Cat with your own custom logo.
I like to use patorjk and the "Epic" font for each project name. It's easier to identify which log file I am currently reading.

Conclusion

I hope you like my template, and I hope I will help you be more productive with MongoDB and the Java stack.
If you see something which can be improved, please feel free to open a GitHub issue or directly submit a pull request. They are very welcome. :-)
If you are new to MongoDB Atlas, give our Quick Start post a try to get up to speed with MongoDB Atlas in no time.

Facebook Icontwitter iconlinkedin icon
Rate this code example
star-empty
star-empty
star-empty
star-empty
star-empty
Related
Tutorial

Spring Data Unlocked: Advanced Queries With MongoDB


Nov 08, 2024 | 7 min read
Tutorial

How to Migrate PostgreSQL to MongoDB With Confluent Kafka


Aug 30, 2024 | 10 min read
Code Example

How to Implement Client-Side Field Level Encryption (CSFLE) in Java with Spring Data MongoDB


Jan 27, 2024 | 11 min read
Tutorial

Serverless Development with AWS Lambda and MongoDB Atlas Using Java


Jul 20, 2023 | 6 min read
Technologies Used
Languages
Technologies
Table of Contents