Getting Started With Server-side Kotlin and MongoDB
Rate this tutorial
Are you a Java developer looking to get started with Kotlin? Maybe you’re a Kotlin developer hoping to use MongoDB. If this is the case, look no further! In this tutorial, we’ll cover how to build a sample REST API using Spring Boot, MongoDB, and the server-side Kotlin driver.
At MongoDB, we’re excited about Kotlin. We released a server-side Kotlin driver in 2022, in response to the growing Kotlin community, many of whom (maybe you!) are former Java developers turning to Kotlin for its interoperability with Java, and its conciseness compared to earlier JVM languages.
This tutorial will cover how to build an application using the Kotlin sync driver. If you’d rather use Kotlin with coroutines to do asynchronous programming, read our tutorial on creating an API with Ktor and MongoDB Atlas If you’d rather use Spring with Java, we have plenty of resources for that too.
To follow along with this tutorial, you’ll need:
- Java 17+.
- An IDE (I’m using IntelliJ).
- Maven or Gradle (you choose—I’m using Gradle!).
Spring Boot allows you to create standalone, production-grade, Spring-based applications easily. Let’s use Spring Initializr to create our project using the following options:
- Project: Gradle - Kotlin
- Language: Kotlin
- Spring Boot: Feel free to leave this on the default selection
We’ll also add in a dependency on Spring Web:
- Spring Web
While we could add an additional dependency on Spring Data MongoDB, we’ll forgo that for now. This is because we want to use the new Kotlin driver, and Spring Data MongoDB, though it does support Kotlin, uses the Java driver underneath. However, do note that Spring Data MongoDB is a fine choice and makes it very easy to get started with MongoDB, especially if you’ve used other Spring Data projects before.
Unzip the project in your IDE of choice (I’m using IntelliJ), and we’re ready to dive in!
To be able to interact with MongoDB from your Kotlin application, we’ll need to add a dependency on the Kotlin sync driver. You can do this by going to your
build.gradle.kts
file.1 dependencies { 2 implementation("org.mongodb:mongodb-driver-kotlin-sync:5.1.4") 3 }
Feel free to change the dependency version to a more recent version of the Kotlin driver. I’m using what’s been most recently released as of the time of writing this article. Refresh Gradle, and we can proceed!
Next, navigate to the
application.properties
file of your Spring Boot auto-generated application (you can find this in src > main > resources
). You’ll want to add in a few things, namely the cluster URI and your database name. If you don’t know what your cluster URI is, have no fear! You can find it easily via the MongoDB Atlas UI.If you don’t already have a cluster deployed in Atlas, I’d recommend pausing this tutorial and following this guide to set up a free-forever cluster and load in sample data. We’ll need both a cluster and the sample data loaded in to be able to continue following this tutorial.
You can sign into MongoDB Atlas and obtain your connection string by going to your Clusters view, and then pressing “Connect” on the cluster you want to connect to. Once you choose “Drivers,” “Kotlin,” and the appropriate version in the drop-down list, you can copy the connection string that’s shown in the modal.
As an example, here’s what mine looks like:
1 spring.application.name=spring-kotlin-sync 2 spring.data.mongodb.uri = mongodb+srv://username:password@host.ejzguta.mongodb.net/?retryWrites=true&w=majority&appName=kotlin-tutorial 3 spring.data.mongodb.database=sample_mflix
For this tutorial, we’ll be using the movies collection in
sample_mflix
(part of the sample dataset), so each document in our collection will represent a movie. You can see some of the fields in the document by going to the Atlas UI and clicking on the movies
collection. You should see something like this:We could create a
Movie
class with the following fields—an id
, title
, the fullPlot
, and the year
the movie was released—as a minimal representation of an individual movie in the collection. The Movie
class would then resemble the following:1 data class Movie( 2 @Id 3 val id: ObjectId = ObjectId(), 4 val title: String = "", 5 val fullPlot: String = "", 6 val year: Int = 0 7 )
However, we can also interact with the individual documents directly. In this tutorial, we’ll forego the
Movie
class and will instead use the documents as they appear in the collection.In the Spring world, HTTP requests are handled by a controller (and annotated as such through the
@RestController
annotation). Create a MovieController
class and annotate it with @RestController
.For demonstration purposes, I’m creating my
MongoClient
directly within my MovieController
, but note that MongoClient should typically live outside of the Controller and can be injected into the Controller with Spring (the MongoDB Developer Center has an example of this configuration). I can use my URI as the parameter for creating a new MongoClient
, then find the database through the getDatabase()
method, and the collection through the getCollection()
method on that database.If we want to find a movie made in a particular release year, we’ll need to use a GET request, as we’ll be requesting data from a resource. We can use the Spring annotation, @GetMapping, to ensure that our HTTP GET request is mapped to the appropriate method.
Let’s map /year to a getMovieByYear() method that will take in a year and return the first matching movie in our database. Note that @RequestParam is how we are able to use the query string parameter “year” in our method. In terms of the actual method, we’re using the collection.find() method and limiting our result set to the first matching document using .first().
1 import org.bson.Document 2 3 4 @RestController 5 @RequestMapping("/movies") 6 class MovieController { 7 8 9 val mongoClient = MongoClients.create(MONGODB_URI) 10 val database = mongoClient.getDatabase("sample_mflix") 11 val collection = database.getCollection("movies") 12 13 14 @GetMapping("/year") 15 fun findMovieByYear(@RequestParam year:Int):Document?{ 16 return collection.find(eq("year", year)).first() 17 } 18 }
So, now that we have the right methods in place, it’s time to run our application! From your IDE, run your application. Once your application has started successfully, navigate to your browser and try to find a movie that matches a particular year.
By navigating to http://localhost:8080/movies/year?year=1999, you’ll get a JSON result that represents the matching
Movie
in your collection.We can take the same concepts of finding a movie by year and apply them to filtering by title. In your
MovieController
, you can create another method, perhaps called findMovieByTitle
, that will take in a title and return the first matching movie in your collection. Make sure you annotate this method with another @GetMapping
, but this time with /title
. To test out your changes, try looking through your collection in Atlas to find a matching title, then search for that same title using your method. If we click through to http://localhost:8080/movies/title?title=Toy Story, the result should be the movie that represents “Toy Story” in your collection.
1 @GetMapping("/title") 2 fun findMovieByTitle(@RequestParam title:String):Document?{ 3 return collection.find(eq("title", title)).first() 4 }
Now that we’ve mastered reading from MongoDB, let’s learn how to write to MongoDB using the Kotlin sync driver. Maybe you want to add a movie that you’ve just watched or load in some newer movies that were created after the dataset was created.
We’ll create another method, this time to add a movie, and annotate it with
@PostMapping
. Similar to @GetMapping
earlier, this annotation maps our POST requests to the right method. I’ve created a fairly minimal Movie
representation as compared to the full Document
in my collection, but because MongoDB is inherently flexible in the data it can hold, this is completely fine!1 @PostMapping("/add")`` fun addMovie(@RequestParam title:String, @RequestParam year:Int, @RequestParam fullPlot:String){`` collection.insertOne(Document("title", title).append("year", year).append("fullPlot", fullPlot))`` }`\
1 curl --location --request POST 'http://localhost:8080/movies/add?title=KotlinDriver&year=2024&fullPlot=ThisIsAPlot'
Alternatively, we can create a form to take in our input. Let’s do the latter. Create an HTML file to add a movie to your database, and map the form’s action to /movies/add using a “post” method:
1 <form action="/movies/add" method="post"> 2 3 4 <!--Take in a title--> 5 <label for="title">Title</label> 6 <input type="text" id="title" name="title">
In this article, we covered connecting to MongoDB using a MongoClient, reading and writing to MongoDB using some of the methods present in the Kotlin driver, and using Spring Boot and Spring Data to help us get started quickly (and to map our methods to the right endpoints). We even created a simple form-based UI to capture and record input!
To go deeper with Kotlin and MongoDB, check out our tutorial on Ktor and Vector Search in Kotlin. It builds on some of the foundational work covered in our earlier Ktor article and is a great starting point for building Kotlin applications with MongoDB.
Top Comments in Forums
There are no comments on this article yet.