REST API With Scala Play Framework and Reactive Mongo

Mahjoub Saifeddine
Geek Culture
Published in
5 min readJan 24, 2021

The basics of building a REST API with the Scala/Play Framework with Reactive mongo.

Introduction

In this post, I’m going to demonstrate how to build an asynchronous & non-blocking REST application using the Play framework and reactive mongo plugin. For the sake of simplicity, in this story, we’ll create a basic API that allows us to perform the basic CRUD operations for the data stored in a mongo database.

Prerequisite

The post is accessible for beginners. However, Scala and Play framework fundamentals are required. Before going any further, please make sure that you have the following tools installed on your local machine.

  • JVM 14
  • Scala 2.13.3
  • Sbt 1.3.13
  • Docker (Optional)

You can set up a local mongo db server using to following commands:

> mkdir mydata
> docker pull mongo:latest
> docker run --name local-mongodb -d -p 27017:27017 -v ~/data:/data/db mongo

The project setup

The first part consists of creating the project and add required dependencies.

Seed the project:

The first step is to create our project skeleton. This can be easily done using this sbt command:

> sbt new playframework/play-scala-seed.g8

You’ll be asked to fill in some basic information about the project such as the name of the package and the organization.

This template generates a Play Scala projectname [play-scala-seed]: movie-store
organization [com.example]:
Template applied in ./movie-store

By the time I’m writing this, the project is generated with Play 2.8. If you’re somewhere in the future, you might get a new version of Play. If so, please consider upgrading the other dependencies as well.

If everything goes well, you should be able to start the application with this command.

> sbt run

Add dependencies:

The reactive mongo plugin for Play 2.8 can be enabled by adding the following dependencies:

Dependencies to enable reactive mongo.

The mongo driver will be resolved automatically as transitive dependency.

To enable dependency injection for reactive mongo module. Add the following line into the application.conf.

Enable dependency injection for reactive mongo.

Configure database access:

The last step is to configure the database access.

Database access

The API

Now that our project is ready, we’ll move on to the next step that consists of creating the models, repositories, and controllers. I’m going to keep the example simple as much as possible but it should be good enough for our purposes.

The model:

Movie Model

As you can see, we have a basic case class that contains the definition of a movie and a companion object that contains the implicit JSON/BJSON serializers.

For JSON serialization we’re using automated mapping. Basically, the Json.format[Movie]macro will inspect the movie case class fields and produce a JSON. On the other hand, for external types, you should provide their serializers as implicit just like the case for DateTime.

For BSON, however, we’re implementing our custom serializer.

The repository:

So, this is our initial version of the movie repository. Basically, it injects the execution context and the reactive mongo api. Also, it contains a helpers function that returns a FutureofBSONCollection.

The `collection` is a function to avoid potential problems in development with play auto reloading.

Once the repository is ready, we can start by adding some basic queries.

Read queries

The find method takes two arguments, the selector and the projection. In nutshell, the selector is used to match specific documents and the projector is used to project-specific fields on the documents. In our case, we want to keep things simple and stick with defaults.

The find method returns a query builder which means the query is therefore not performed yet. It allows you to add options to the query, like a sorting ordering.

You can learn more about the find in the mongo documentation.

Write queries

Now, you can see the write queries. The insert insert method returns an InsertBuilder instance which you can use to insert one or many documents. Same thing for update and delete methods which return an UpdateBuilder and DeleteBuilder respectively.

The controller

Now, we reached the last part. We’ll create the endpoints to expose the actions for the movies repository.

Let’s start by creating the controller:

Now, we’ll create the two endpoints responsible of reading data:

Read data endpoints

We have two endpoints, the first one will return the movie list and the second one will parse the given id and return the associated movie if it’s found.

Create/Update/Delete endpoints

Besides validating the id passed in an argument like the previous code. Also, we check if the json is valid by using the validate helper in the request body.

Thanks to the json serialization macro created in the previous section, the Scala object can be serialized implicitly from json and vise-versa.

Routes

The last part is the bind the controller methods to their routes.

Testing the API

Now that our application is ready we can make simple tests with `cURL`.
Let’s start by creating a movie.

> curl --verbose --header "Content-Type: application/json" \
--request POST \
--data '{ "title":"My favorite movie", "description":"My favorite movie description" }' \
http://localhost:9000/movies

If everything is working, you should get a similar result.

< HTTP/1.1 201 Created
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Permitted-Cross-Domain-Policies: master-only
< Date: Sun, 10 Jan 2021 12:25:06 GMT
< Content-Type: application/json
< Content-Length: 75
{
"title": "My favorite movie",
"description": "My favorite movie description"
}*

Now with a `GET` request:

> curl --verbose --request GET http://localhost:9000/movies

Again, you should get a similar result.

< HTTP/1.1 200 OK
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Permitted-Cross-Domain-Policies: master-only
< Date: Sun, 10 Jan 2021 12:47:34 GMT
< Content-Type: application/json
< Content-Length: 213
[
{
"_id": {
"$oid": "5ffaf5b787901a6769f585f8"
},
"_creationDate": "2021-01-10T13:40:23.359+01:00",
"_updateDate": "2021-01-10T13:40:23.359+01:00",
"title": "My favorite movie",
"description": "My favorite movie description"
}
]*

Conclusion

In this post, we saw a basic example of creating a restful API with Play, on the top of a mongo database. You can find the code solution in my Github. Thank you.

--

--