How-tos

Getting started with Microservices using Spring Boot and Cloudant

Share this post:

IBM Architecture Center As part of developing cloud-native business applications, the microservices architecture has gained popularity because it simplifies the delivery of independently packaged and deployed application units as part of a larger application. By breaking down large monolithic applications into components of a microservices-based application, teams can work more independently. Additionally, thanks to devops continuous integration/continuous delivery tools, new application functionality can be delivered as its completed in an automated, replicable fashion.

In this brief how-to, you’ll learn how to create a simple microservice that manages product reviews in a Cloudant NoSQL database. The example code is written in Java and leverages the Spring Boot framework. It provides basic operations of saving and querying social review comments in the Cloudant database hosted on IBM Bluemix platform.

This small sample is a modified excerpt of a larger, more complex microservices-based retail web and mobile application that is one of the IBM Cloud Architecture Center reference implementations depicted below:


Review microservice described in this post is highlighted above (in context of larger reference architecture implementation)

In the next installment of this series, I’ll walk you through how to package this Spring Boot application as a Docker container and deploy to a Bluemix container runtime.

Get development tools, provision service, get code

There several ways to access a Cloudant database in a Spring Boot application (actually Java app) such as java-cloudant, ektorp, jcouchdb etc. You can see all these libraries here. I decided to use java-cloudant library because it is an official library from IBM and worked well with the Spring Boot framework.

Step 1: Download and install development tools

To complete this tutorial, you will need the following:

Once you’ve installed the above tools, begin by cloning the sample application from GitHub to your local environment:

git clone -b springboot https://github.com/ibm-cloud-architecture/refarch-cloudnative-micro-socialreview.git

Step 2: Provision a Cloudant service in Bluemix

To provision the Cloudant service, you must have a Bluemix account. Login to your Bluemix account or register for a new account (it’s free).

To create the Cloudant service, go to the catalog: console.ng.bluemix.net/catalog/services/cloudant-nosql-db (remember to login to your Bluemix account). Give your Cloudant service a name like refarch-cloudantdb (select the Rename Service choice under the ACTIONS dropdown in the list of services).

For testing, you can select the “Lite” plan, then click “Create”. Once created, open the credentials tab and note your Cloudant Service credentials, for example:

{
 'username': '3xxxx-44f0d2add79e-bluemix',
 'password': 'xxxxxxxxxxxxxxxxxxxxxx',
 'host': 'xxxxx-bluemix.cloudant.com',
 'port': 443,
 'url': 'https://xxxxx-bluemix.cloudant.com'
}

Clicking the “Launch” button will open the Cloudant management console. It’s empty now.

Step 3: Build the sample application with Gradle

Now, you can work on the application. Spring Boot application can be built with either Gradle or Maven. For this how-to, the instructions are for Gradle.

Navigate into the GitHub repository root folder refarch-cloudnative-micro-socialreview; you should find the build.gradle file in that folder. It defines the library dependencies and basic build configuration such as built output. The app uses the following dependencies:

    compile("org.springframework.boot:spring-boot-starter-web:1.4.0.RELEASE") {
        exclude module: "spring-boot-starter-tomcat"
    }
    compile("org.springframework.boot:spring-boot-starter-jetty:1.4.0.RELEASE")
    compile("org.springframework.boot:spring-boot-starter-actuator:1.4.0.RELEASE")
    compile group: 'com.cloudant', name: 'cloudant-client', version: '2.5.1'
    compile("junit:junit")
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '1.4.0.RELEASE'

Notice the dependency cloudant-client; it will assure that the Cloudant Java library will be downloaded and added to the project when you build it. When you run the Gradle build later, all the dependencies will be downloaded when it is first run.

Code walkthrough

With Spring Boot, building cloud-native microservices app is pretty easy and straightforward. Let’s take a look at the code. Under the root directory, most of the files and folders are build-related. The application code is managed under the src folder. I’ll review these four classes:

  • socialreview.cloudant.Application – bootstrap and server
  • socialreview.cloudant.Review – entity representation of a review in the database
  • socialreview.cloudant.ReviewRestController – microservice REST API for reviews
  • socialreview.cloudant.ReviewRestControllerTest – sniff test of microservice REST API for reviews

Code review: src/main/java/socialreview/cloudant/Application.java

This is the bootstrap class that loads the web application and starts an embedded server.

@SpringBootApplication
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(EnvironmentConfig.class, args);
        System.out.println("SocialReview Spring Boot Microservice is ready on IBM Bluemix");
    }

The @SpringBootApplication is a convenience annotation that loads useful Spring components such as the @Configuration, @ComponentScan and @EnableAutoConfiguration. It also adds the Spring webmvc to the classpath and activates the DispatcherServlet to start handling request.

The main function invokes SpringApplication.run to bootstrap the application. The first parameter EnvironmentConfig.class (a custom class) tells the Spring Boot application to load Cloudant and application configuration from the /src/main/resources/application.yml file. The other function creates a Cloudant database object that can be used by the REST controller later.

    @Resource
    private CloudantConfig dbconfig;

    @Bean
    public Database cloudantclient () {

      Database db = null;
      try {
        CloudantClient client = ClientBuilder.url(new URL(dbconfig.getHost()))
                    .username(dbconfig.getUsername())
                    .password(dbconfig.getPassword())
                    .build();

          //Get socialReview db
          // Get a Database instance to interact with, but don't create it if it doesn't already exist
          db = client.database("socialreviewdb", true);
          System.out.println(db.info().toString());
      }catch (Exception e)
      {
        e.printStackTrace();
      }
    return db;
  }

The code does the following:

  • Inject a CloudantConfig object that reads the cloudant/application configuration information from the resource/application.yml file.
  • Create a Cloudant client object using the configuration information (username, password and host)
  • Fetch or create (when the second parameter is true) a Cloudant database object from the client object
  • Return the database object to the Spring framework so other components can use it.

Code review: src/main/java/socialreview/cloudant/Review.java

This is an entity class that maps to the document saved in Cloudant NoSQL database. Spring Boot framework will automatically serialize the entity object with the response from the Cloudant database as well as convert it to JSON when sending the request back for the REST request.

public class Review {

  private String _rev;
  private String _id;
  private String comment;
  private int itemId;
  private int rating;
  private String reviewer_email;
  private String reviewer_name;
  private String review_date;

  public Review(){}

  public Review(boolean isStub)
  {
    this.comment = "It works";
    this.itemId = 13401;
    this.rating = 5;
    this.reviewer_email = "gc@ibm.com";
    this.reviewer_name = "Gang Chen";
    this.review_date = "08/18/2016";
  }

Code review: src/main/java/socialreview/cloudant/ReviewRestController.java

This is the main class that exposes the REST API and interacts with the Cloudant database to perform save and query operations.

@RestController
@RequestMapping("/review")
public class ReviewRestController {

  @Autowired
  private Database db;

The @RestController tells the Spring MVC to handle web requests with the root web context root as review. I also used the @Autowired annotation to do dependency injection for the Cloudant database initiated earlier in the Application bootstrap class.

// Create a new review
  @RequestMapping(method = RequestMethod.POST, consumes = "application/json")
  public @ResponseBody String saveReview(@RequestBody Review review) {

    // Mock data for testing
    //db.save(new Review(true));
    //Review doc = db.find(Review.class,"111");
    //return doc.toString();
    System.out.println("Save Review " + review);
    Response r = null;
    if (review != null) {
        r = db.post(review);
    }
    return r.getId();
  }

This code saves/persists a review comment document into the Cloudant database. It is a POST request. The Cloudant Java client makes the persistent very simple with a single API call, db.post(review), shown above. On the other hand, the GET (query) function is a little bit more complex.

// Query reviews for all documents or by ItemId
  @RequestMapping(method=RequestMethod.GET)
  public @ResponseBody List getAll(@RequestParam(required=false) Integer itemId) {

    // Get all documents from socialreviewdb
    List allDocs = null;
    try
    {
      if(itemId == null)
      {
        allDocs = db.getAllDocsRequestBuilder().includeDocs(true).build().getResponse()
            .getDocsAs(Review.class);
      }else{
          // create Index
          // Create a design doc named designdoc
          // A view named querybyitemIdView
          // and an index named itemId
		      db.createIndex("querybyitemIdView","designdoc","json",
				      new IndexField[]{
                	new IndexField("itemId",SortOrder.asc)
                        }
		      );
          System.out.println("Successfully created index");
          //allDocs = db.findByIndex("{\"itemId\" :\"" + itemId + "\"}", Review.class);
          allDocs = db.findByIndex("{\"itemId\" : " + itemId + "}", Review.class);
      }
    } catch (Exception e) {
				System.out.println("Exception thrown : " + e.getMessage());
		}
    return allDocs;
  }

The @RequestParam(required=false) Integer itemId parameter allows you to query the entire review documents or just all reviews associated with a specific itemId. Getting all documents is easy, as there is a built-in API from Cloudant Java library to do that.

Query by itemId is slightly more complex. Cloudant database typically uses the MapReduce mechanism to perform queries. To achieve this, normally you will create an index and save that in the design document (a special Cloudant document). It will only be created once at the first use. Once the index is created, the query can be performed by invoking the index using db.findByIndex().

The returned object will be serialized as a Review entity object in JSON format.

Code review: src/resources/application.yml

# Spring properties
spring:
  application:
     name: socialreview-microservice

# Server configuration
server:
  context-path: /micro
  port: 8080

# Cloudant Confiugration
cloudant:
  username: 
  password: 
  host: 

This file defines the application configuration such as name of the application, the base URL for the web app and which port it runs on. I also put the Cloudant configuration information in this file. You need to update the cloudant configuration section to fill in the Cloudant instance credentials you created earlier.

Code review: src/test/java/socialreview/cloudant/ReviewControllerTest.java

I’ve written a simple integration test case to validate that the connection to Cloudant is successful and able to fetch all the documents. Once the test case is added to the project structure, it will automatically be recognized by the build system. You can follow the instruction later to run the test case.

Build and Run the application

Once you have Cloudant configured, update the src/resources/application.yml file for the Cloudant credential:

  • username
  • password
  • host

Under the repository root directory, run the following command to build the application:

$ cd refarch-cloudnative-micro-socialreview
$ ./gradlew build -x test

Make sure that the application build completes successfully. It will package the compiled application under build/libs directory. Now, you can run the application with the following command:

$ java -jar build/libs/micro-socialreview-0.1.0.jar

Yes, the final distribution of the application is in a jar file and all you need to run is to execute the Jar file. The application should be running at port 8080. Open a browser with following URL:

http://localhost:8080/micro/review

This will return all the reviews in the database. You can use Chrome POSTMAN to insert a new review document. Or use the following curl command to insert a review comment:

curl --request POST \
  --url 'http://localhost:8080/micro/review' \
  --header 'accept: application/json' \
  --header 'content-type: application/json' \
  --data '{"comment": "Nice product","itemId": 13402,"rating": 3,"reviewer_email": \
           "gangchen@us.ibm.com","reviewer_name": "Gang Chen","review_date": "12/31/2017"}'

It should return a Cloudant document ID upon successful execution. You can validate the operation by hitting the GET URL again:

http://localhost:8080/micro/review?itemId=13402

The saved review comment should be returned. Alternatively, you can launch the Cloudant database console and review the documents there as well. I also provided a simple integration test case that you can run with:

$ ./gradlew test

Next: Leveraging containers to simplify deployment and scalability

This post showed you how easily you can build a microservice application to access a Cloudant database using Spring Boot and Cloudant Java client. But it is not that exciting to run the application locally. To demonstrate how the microservice architecture simplifies delivering scalability, the next post in this series will describe how to package the Social Review Spring Boot application as a Docker image, test the Docker container locally, and deploy and run it on IBM Bluemix platform.

References

More How-tos Stories

Centralized Configuration for Spring Apps on Bluemix Kubernetes

In this tutorial, we'll adapt the Centralized Configuration guide from the Spring website to be deployed to Bluemix Kubernetes. We'll host our configuration files in a Github repository. Before getting started, you should follow the guide or download the complete version.

Continue reading

Monitoring & logging for IBM Bluemix Container Service with Sematext

In this blog post we discuss how Sematext integrates with IBM Bluemix Container Service to provide monitoring and logging visibility of your containerized applications, as they run in production. In the sections below, we demonstrate how to set up a Kubernetes cluster in Bluemix and how to set up Sematext in this cluster. IBM Cloud has monitoring and logging capabilities in the platform, but we know our customers operate in a multi-cloud or hybrid cloud environment and we are very excited to partner with Sematext, enabling operational consistency across those environments. We worked with Alen Komljen, an Automation Engineer from Sematext, to create the following content and perform the technology validation.

Continue reading

99.95% availability. Balancing release velocity and reliability

Availability and reliability are rarely at the front of developers minds when delivering new applications on Bluemix. The ease and speed of creating and deploying new features is very seductive.

Continue reading