Creating web-app using Kotlin, Java, Spring Boot & MongoDB

This blog is a part of building scalable Spring Boot microservices based project. It comprises of creating connecting microservices using Zuul, service discovery using Consul, security using Spring Security, distributed session using Spring Session and products such as MongoDB, Redis. Here is the chronological sequence of how I wrote article. https://medium.com/@nepalBrothers/web-development-scalable-web-app-using-spring-boot-and-spring-cloud-1f9960e1d61a

Spring Boot has made it faster to write a web-app. It takes care of lots of configuration and leaves us little to configure. MongoDB is a NO-SQL database that stores the data in a document format. It does not have any structure like Relational Databases have and therefore has both pros and cons.

What we will do here is create web-app that provides the information about the laptop products. It will first store the products information in the MongoDB using the Spring Data and then exposes the product information to the users using REST-API.

To check the code, see here: https://github.com/rockink/product

Create A Spring App

We can use Spring Initializer to create a project skeleton for us. Since we are using Kotlin, we need to make sure that the code we are generating is for Kotlin.

We will need following dependencies

  1. MongoDB to use Spring Data MongoDB
  2. Web to make our Spring Boot app a web-app

Architecture

We will use Model-View-Controller MVC Architecture to implement this. Following Architecture pattern is a good habit while designing the project.

When the user makes a HTTP call to our Product web-app, we will design our app in such a way that ProductController class will handle the REST-API implementation. ProductController will then make a call to ProductService, which is responsible for handling the business logic and we will have ProductRepository to provide database communication for our web-app.

Product Model

We will now create a class to hold the information about Laptops. We will provide each laptop with a unique id.

package com.test.product.models

import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.mapping.Document

@Document
data class Product(
@Id var id: String,
var name: String,
var company: String,
var productType: String,
val price: Float,
val sizeInch: Float,
val screenResolution: String,
val cpu: String,
val ram: Int,
val storage: String,
val gpu: String,
val opSys: String
);

Good thing about Kotlin is that we can create a class to hold a data. Doing so, Kotlin automatically generates toString(), equals(), hashCode() methods for us. This way, we don’t have to write a code for them. Yayy!!

There is an annotation @Document on the top of the class which basically tells Spring MongoDB to consider this as MongoDb document. And, @Id to tell Spring MongoDB to consider it as id.

Product class is a representation of the data we are going to save into or pull from the MongoDB. Therefore, this requires us to create a connection between MongoDb and our project.

Running MongoDB

We will need to run the MongoDB in order for our application to communicate with it. Luckily, Spring Boot automatically connects our app with it when MongoDB is run in its own default port.

I like the way of not cluttering my laptop, so what I instead did was installed Docker on my machine. Docker sandboxes the MongoDB for us in its container. We can then tell the Docker to run MongoDB in the port we want.

Here is a blog of how I use to run MongoDB on my machine.

Communicating with MongoDB via Repository Layer

Good part of Spring Boot is that MongoDB is connected without any additional configuration from our side if everything is set as default. Once we have the Spring Data MongoDb dependency in our classpath, it sets up port and everything for us. However, if you need to customize it, for instance, setting username/password, you can do that as well.

Create a Product Repository

Creating a Product Repository is simple. We just need to extend Repository

interface ProductRepository: MongoRepository<Product, String>;

This automatically generates some API such as save, findById, delete, findAll. We will make a use of these.

Creating a Product Service

Product Service is where our business logic resides. In our simple web-app, we have these requirements:

  1. Provide a list of all products
  2. When asked for a product given a product id, provide that product
@Service
class ProductService(val productRepository: ProductRepository){


fun getAllProducts(): Collection<Product> {
return productRepository.findAll();
}

fun getProductDetailById(id: String): Product? {
val product = productRepository.findById(id);
if(!product.isPresent) {
throw ProductNotFoundException("Product id=$id not found")
}
return product.get();
}
}

Lets go through them:

  1. productRepository is the repository we implemented in the step above it. Having it in a constructor means that we are letting Spring’s Dependency Injection to provide us the productRepository implementation for us.
  2. @Service annotation means that we are telling Spring Boot to consider this as a Bean, meaning that we are telling Spring “Hey Spring, this class is a service. Consider it as a service and provide my application whenever my application needs.”
  3. ProductNotFoundException is exception in the project when the product is not found.

Expose API via ProductController

In the below implementation, we are exposing the ProductController by annotating it with @RestController.

Let Spring bootstrap this application

Spring does not automatically work. We will need to bootstrap our application so that it gets in the Spring environment. Luckily, IDEs usually automatically create it for you. We do so by:

public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}

But where is the Product data we need for app?

At this point, we haven’t loaded up the Product. I downloaded the Laptop information from Kaggle which is in csv format and uploaded <root directory>/data folder directory.

We will need to upload these products in our database in the first place. Spring provides us an interface CommandLineRunner to implement run method. We can implement that to load the data in the database.

And the DummyProdutRepoPopulator class is below:

Run the project

After making sure that MongoDB is running, we can run this application. After that, we can test it using curl or in the browser by going to

http://localhost:8080

curl http://localhost:8080/1
{"product":{"id":"1","name":"MacBook Pro","company":"Apple","productType":"laptop","price":1339.69,"sizeInch":13.3,"screenResolution":"IPS Panel Retina Display 2560x1600","cpu":"Intel Core i5 2.3GHz","ram":8,"storage":"128GB SSD","gpu":"Intel Iris Plus Graphics 640","opSys":"macOS"}}