Wednesday, December 30, 2015

Documenting REST APIs with Swagger

Our REST API for managing geek diary entries is getting into shape. But APIs are meant to be used and making an API easy to use requires good documentation. In this post we will use Swagger for documenting our REST API. Swagger is a simple yet powerful representation of APIs. It maintains an ecosystem of tools that facilitate the easy documentation, client generation and discoverability of APIs. In this tutorial is presented how Swagger can be used to document a REST API and then the Swagger UI tool will be employed for beautiful web-based representation of the geek diaries API specification. I should note that the tutorial also uses the springfox framework which helps the generation of automated API documentation for APIs built with Spring.

Let's start by extending our pom.xml file with the necessary dependencies:

<!-- Swagger -->
<dependency>
  <groupId>io.swagger</groupId>
  <artifactId>swagger-core</artifactId>
  <version>1.5.4</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.3.0</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.3.0</version>
</dependency> 


There are few additions we need to to in our existing code base. We will create a new class named SwaggerConfig with some configuration and information about our REST API, we will declare the class in the WebAppInitializer and we will annotate our web service methods to be "picked up" by swagger. The project structure at the end will look like in the following figure:



The newly created SwaggerConfig class is as following:
package com.tasosmartidis.rest_api_tutorial.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.any()) 
            .paths(PathSelectors.any()) 
            .build()
            .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        ApiInfo apiInfo = new ApiInfo(
            "Geek Diaries REST API",
            "This is a REST API for managing diary entries.",
            "v0.1",
            "API TOS",
            "martidis.tasos@gmail.com",
            "API License",
            "API License URL"
        );
        return apiInfo;
    }
}


Now we will update the WebAppInitializer to add the SwaggerConfig  in the servlet configuration classes:
package com.tasosmartidis.rest_api_tutorial.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {RootConfig.class, SpringMongoConfig.class, SecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {WebConfig.class,SwaggerConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }

}


Finally, we annotate our service methods to inform parties interested in our API about their purpose, input, output and similar. Besides the swagger annotations, the existing annotations for implementing the REST API are also utilized. The updated rest-controller class is shown below:
package com.tasosmartidis.rest_api_tutorial.web;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.tasosmartidis.rest_api_tutorial.data.DaoMongo;
import com.tasosmartidis.rest_api_tutorial.data.DiaryEntry;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
 
@RestController
@RequestMapping("/service/geek-diaries")
@Api(value = "/service/geek-diaries", description = "CRUD operations on the Geek Diaries datastore")
public class DiaryService {
    
    @Autowired
    DaoMongo dao; 
    
    @RequestMapping(value="/entry/{entryId}", method=RequestMethod.GET)
    @ApiOperation(value = "Retrieves a diary entry",
            notes = "The specified id is used to retrieve and return the diary entry",
            response = DiaryEntry.class)
    public ResponseEntity<DiaryEntry> getDiaryEntry(@PathVariable String entryId) {
        DiaryEntry diaryEntry = dao.getDiaryEntry(entryId);
        
        return new ResponseEntity<DiaryEntry>(diaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/", method=RequestMethod.POST)
    @ApiOperation(value = "Creates a new diary entry that will be persisted in the database", 
            notes = "On success the newly created diary entry will be returned to the user along with the HTTP code",
            response = DiaryEntry.class)
    public ResponseEntity<DiaryEntry> createDiaryEntry(@RequestBody DiaryEntry newEntry) { 
         DiaryEntry newDiaryEntry = dao.createDiaryEntry(newEntry);

        return new ResponseEntity<DiaryEntry>(newDiaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/", method=RequestMethod.PUT)
    @ApiOperation(value = "Updates diary entry if attributes have changed", 
            notes = "On success the updated diary entry will be returned to the user along with the HTTP code",
            response = DiaryEntry.class)
    public ResponseEntity<DiaryEntry> updateDiaryEntry(@RequestBody DiaryEntry newEntry) { 
         DiaryEntry updatedDiaryEntry = dao.updateDiaryEntry(newEntry);

        return new ResponseEntity<DiaryEntry>(updatedDiaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/{entryId}", method=RequestMethod.DELETE)
    @ApiOperation(value = "Deletes a specified diary entry from the database", 
            notes = "Removes a diary entry based on its specified and unique id. On success the id is returned to requester",
            response = String.class)
    public ResponseEntity<String> deleteDiaryEntry(@PathVariable String entryId) { 
         String deletedDiaryEntry = dao.deleteDiaryEntry(entryId);

        return new ResponseEntity<String>(deletedDiaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/", method=RequestMethod.GET) 
    @ApiOperation(value = "Retrieves all diary entries persisted in the database", 
            response = DiaryEntry.class,
            responseContainer = "List")
    public ResponseEntity<Map<String, DiaryEntry>> getDiaryEntries() { 
        Map<String, DiaryEntry> diaryEntries = dao.getAllDiaryEntries();

        return new ResponseEntity<Map<String, DiaryEntry>>(diaryEntries,HttpStatus.OK); 
    }
}


And that's about it! We package the application to a war and deploy on tomcat or similar. The use of the Swagger UI tool provides us with a very user friendly description of the API.

The online documentation can be find in the /root/path/of/api/swagger-ui.html. In my case it is http://localhost:9989/rest-api-tutorial/swagger-ui.html. What you would see looks something like this:

This is the generic high level overview, but by clicking in each method, a detailed specification and examples are presented. For example the POST method:

And the PUT method: 

















































Looks nice and handy don't you think? As a fellow geek I hope you document your REST APIs (with Swagger or not) because who knows, we may have to use eachother's APIs! The code is as always available in GitHub.

Tuesday, December 22, 2015

Securing REST APIs with Spring Security (Basic Authentication)

In the previous post we added persistence to our REST API tutorial using Spring Data and MongoDB.  Next we will secure the API, starting from the simplest security mechanism, basic access authentication. In basic authentication, clients of services provide username and password along with their requests. In this tutorial, we will use Spring Security to implement the authentication and restrict access requests on the URL level. The tutorial builds on the initial REST API with the added persistence.

The structure of the project is depicted in the following figure:


We have extended the pom.xml file to add the Spring dependencies for security as shown in the source code below:
<!-- spring security -->
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core</artifactId>
        <version>${spring.security.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>${spring.security.version}</version>
    </dependency>   
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>${spring.security.version}</version>
    </dependency>       

Our security will essentially be implemented by filtering requests which are sent to the servlets. Since Spring 3.2 the configuration of the security has been simplified and can be achieved using annotations. The SecurityConfig class will extend the WebSecurityConfigurerAdapter and use the @EnableWebSecurity annotation to well, enable web security. In the SecurityConfig class we will override a few methods to grant access credentials to users (persisted in-memory) and to specify the HTTP requests and method that have to be authenticated and who has access to them. All these configurations are shown in the class below:
package com.tasosmartidis.rest_api_tutorial.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration 
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {      
        auth
            .inMemoryAuthentication()
                .withUser("tasos").password("tasos").roles("USER","ADMIN")
                .and()
                .withUser("guest").password("guest").roles("USER");
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {      
        http
            .httpBasic()
            .and()
            .authorizeRequests() 
            .antMatchers(HttpMethod.DELETE).hasRole("ADMIN")
            .antMatchers(HttpMethod.GET).hasAnyRole("USER","ADMIN")
            .antMatchers(HttpMethod.POST).hasAnyRole("USER","ADMIN")
            .antMatchers(HttpMethod.PUT).hasAnyRole("USER","ADMIN")
            .and()
            .requiresChannel()
            .antMatchers("/").requiresSecure()
            .and()
            .csrf().disable();
            
    }
}

As shown in the source code above, we use in-memory persistence for assigning roles to pairs of usernames and their passwords (of the users) and we configure the security details for the intercepted incoming requests. We define basic authentication, and based on the type of request we allocate rights to "simple" users and administrators. In our example we allow users to do create, retrieve and update data, but only administrators can delete them. The rights allocation is not really intended to make sense, but we showcase how different rights can be provided to different kind of users. Next,we define that any request mapped to the URL must use a secure channel. Finally, for sake of simplicity we disable csrf (cross-site request forgery) which is enabled by default from WebSecurityConfigurerAdapter.

We also need to configure the DelegatingFilterProxy which is a special servlet filter to intercept incoming requests and apply the security we enabled in the previous class. Once again, Spring makes this easy for us. We just need to extend AbstractSecurityWebApplicationInitializer which implements WebApplicationInitializer and will be discovered by Spring to register the DelegatingFilterProxy with the web container. 
package com.tasosmartidis.rest_api_tutorial.config;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

Finally we have to register our security configuration to WebAppInitializer class we defined in the previous tutorials for our REST API and we are good to go! The updated WebAppInitializer is:
package com.tasosmartidis.rest_api_tutorial.config;


import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {RootConfig.class, SpringMongoConfig.class, SecurityConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }

}

Everything else stays the same, and we are ready to test our application. We will again use POSTMAN for calling the services. First let's try to create new entries with 'bad' credentials

As is shown in the figure above, the attempt to create new diary entry with bad credentials resulted in an HTTP 401 (bad credentials) response. Let's try to do the same request with our credentials for guest users:
  The guest user, which is assigned with the role 'USER' can perform as configured GET, POST and PUT requests and thus the POST operation above was successful! We will update the entry trying one of the other allowed operations:

Again, as expected, the operation was successful! But what would happen if the user guest would attempt a DELETE request?

Access was denied! This is actually what we wanted to see, since only users with role ADMIN are allowed to delete entries in our application. We have the user tasos, who has ADMIN role. Let's try again the request with his credentials:

The DELETE request was successful! And this concludes this tutorial on basic authentication of REST APIs using Spring. Next posts will help us document our REST API and then we will explore other mechanisms for security. As always, the code is available on GitHub.

Monday, December 7, 2015

MongoDB with Spring Data tutorial

A few posts before I presented a tutorial on developing REST APIs and I promised that I would make the example a bit more realistic by adding proper persistence layer, security and so on. It is time to make good on that promise and add persistence on MongoDB database using the Spring Data framework.

If you haven't seen my tutorial on REST APIs you are highly encouraged to do  so before reading this tutorial. If you did I will refresh your memory on the scenario of the tutorial. In the tutorial we built an application that manages (geek) diary entries. The application exposed a REST API which is used to perform CRUD operations on diary entries.

The requirements for replicating and running the tutorial were:

  • JDK 1.7 or higher
  • Maven 
  • Server such as Tomcat 7 or higher
  • Git
  • use of IDE such as eclipse is also advised

and now for the extended version of the tutorial, a running instance of MongoDB is required.

The setup of the project is simple: the ‘config’ package contains the configuration classes for Spring, the ‘data’ package contains our diary entries POJO and the DAOs for data persistence, and finally, in the ‘web’ package is placed the controller with the rest services. The setup is presented in the figure below:

We will not go over all classes again but present only the new or changed ones. Let's start by the new Maven dependencies. We introduce the Spring Data framework in order to communicate with our Mongo database.
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>${spring.data.version}</version>
</dependency>   

Also, I added some logging dependencies because I faced a couple of hiccups while developing. The complete pom.xml file is presented below for the convenience of the reader.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.tasosmartidis</groupId>
  <artifactId>rest-api-tutorial</artifactId>
  <packaging>war</packaging>
  <version>0.1</version>
  <name>rest-api-tutorial Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
  <properties>
        <springframework.version>4.0.6.RELEASE</springframework.version>
        <spring.data.version>1.8.1.RELEASE</spring.data.version> 
    </properties>
    
  <dependencies> 
   <!-- Spring -->
   <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${springframework.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${springframework.version}</version>
    </dependency>    
    
    <!-- Added for the MongoDB persistence - start --> 
    <!-- Spring data mongodb -->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-mongodb</artifactId>
        <version>${spring.data.version}</version>
    </dependency>   
    <!-- Added for the MongoDB persistence - end -->
    
    <!-- logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.5.6</version>
        <type>jar</type>
    </dependency>
    <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-simple</artifactId>
         <version>1.5.6</version>
    </dependency> 
        
    <!-- javax -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp.jstl</groupId>
        <artifactId>jstl-api</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.1</version>
    </dependency>
    <!-- Jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.3.0</version>
    </dependency>   
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.3.0</version>
    </dependency>    
    <!-- JUnit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency> 
  </dependencies>
  
  <build>
    <finalName>rest-api-tutorial</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.9</version>
            <configuration>
                <downloadSources>true</downloadSources>
                <downloadJavadocs>true</downloadJavadocs>
            </configuration>
        </plugin>   
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
              <failOnMissingWebXml>false</failOnMissingWebXml>
            </configuration>
        </plugin>   
    </plugins>
  </build>
</project>

For configuration we used the WebAppInitializer class which has only 3 methods. The getServletMappings() indicates the paths in which the DispatcherServlet will be mapped to. We map it to the default servlet which will handle all requests coming into our application.  The getServletConfigClasses() handles the configuration for the DispacherServlet. The getRootConfigClasses() handles the configuration of the application context created by ContextLoaderListener. In the getRootConfigClasses() method we will add a new class that handles the configuration of our database. The WebAppInitializer now looks like this:
package com.tasosmartidis.rest_api_tutorial.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {RootConfig.class, SpringMongoConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
}

The new SpringMongoConfig class facilitates us to work with MongoDB via Spring. We define the database name we work with, which is "geek_diaries", the location of our database (local) to connect to and a bean for creating the MongoTemplate object which provides implementation of MongoOperations. SpringMongoConfig is presented in the following source code:
package com.tasosmartidis.rest_api_tutorial.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;

import com.mongodb.Mongo;
import com.mongodb.MongoClient;

@Configuration
public class SpringMongoConfig extends AbstractMongoConfiguration {

    @Override
    protected String getDatabaseName() { 
        return "geek_diaries";
    }

    @Override
    @Bean
    public Mongo mongo() throws Exception { 
        return new MongoClient("127.0.0.1");
    }
    
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongo(),getDatabaseName());
    }
}

As the reader probably remembers, our REST API exposed services for performing CRUD operations. We had a DaoMock object that implemented the Dao interface:
package com.tasosmartidis.rest_api_tutorial.data;

import java.util.Map;

public interface Dao {

    public DiaryEntry createDiaryEntry(DiaryEntry newEntry);
    
    public DiaryEntry getDiaryEntry(String entryId);
    
    public DiaryEntry updateDiaryEntry(DiaryEntry updatedEntry);
    
    public String deleteDiaryEntry(String entryId);
    
    public Map<String,DiaryEntry> getAllDiaryEntries();
}

Our new DaoMongo class will implement this interface and will take care of performing CRUD on the actual Mongo instance for our REST API. The class will be presented first and then some comments will follow about its implementation.
package com.tasosmartidis.rest_api_tutorial.data;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.tasosmartidis.rest_api_tutorial.config.SpringMongoConfig;


@Repository("daoMongo")
@Transactional
public class DaoMongo implements Dao {

    private MongoOperations mongoOperations;
    
    public DaoMongo() {
        mongoOperations = loadMongoConfiguration();
    }
    
    public DiaryEntry createDiaryEntry(DiaryEntry newEntry) {       
        // The DiaryEntry instance will have the ID assigned to it automatically
        mongoOperations.save(newEntry);
        
        return newEntry;
    }

    public DiaryEntry getDiaryEntry(String entryId) {
        // query to search diary entries. We will retrieve entries with their specified unique ID 
        Query searchQuery = new Query(); 
        searchQuery.addCriteria(Criteria.where("entryId").is(entryId)); 
        
        // retrieve the specified DiaryEntry from database
        return mongoOperations.findOne(searchQuery,DiaryEntry.class);       
    }

    public DiaryEntry updateDiaryEntry(DiaryEntry updatedEntry) {
        
        // If entry with the same id exists, it updates the entry
        mongoOperations.save(updatedEntry);
        
        // note that we could also use 'Update' object and e.g., its 'set' method
        // to update individual fields of an entry
                
        return getDiaryEntry(updatedEntry.getEntryId());
    }

    public String deleteDiaryEntry(String entryId) {
        Query searchQuery = new Query(); 
        searchQuery.addCriteria(Criteria.where("entryId").is(entryId));
        
        // delete the specified DiaryEntry from database
        mongoOperations.remove(searchQuery,DiaryEntry.class); 
        
        return entryId;
    }

    public Map<String, DiaryEntry> getAllDiaryEntries() {
        List<DiaryEntry> allEntries = mongoOperations.findAll(DiaryEntry.class); 
        return putEntriesToMap(allEntries);
    }
    
    private Map<String, DiaryEntry> putEntriesToMap(List<DiaryEntry> allEntries) {
        Map<String, DiaryEntry> mapWithEntries = new HashMap<>();
        
        for(DiaryEntry entry : allEntries) {
            mapWithEntries.put(entry.getEntryId(), entry);
        }
        
        return mapWithEntries;
    }

    private MongoOperations loadMongoConfiguration() {
        @SuppressWarnings("resource")
        ApplicationContext applicationContext = 
                 new AnnotationConfigApplicationContext(SpringMongoConfig.class);
        MongoOperations mongoOperation = (MongoOperations) applicationContext.getBean("mongoTemplate");
        
        return mongoOperation;
    }

}

The class has a private method loadMongoConfiguration() which is called in its constructor and provides a MongoOpetations object. We use this object to perform CRUD operations in our different methods. In our methods we do not have any exception handling; it is not required by Spring framework for the CRUD methods and we do not add any for simplicity and readability of the code. But in a real world application we would provide such exception handling. Also, when the tutorial was created the scenario was a simple idea and not very well examined, just defined some methods. In order to keep the implementation of the interface we added some processing such as the putEntriesToMap() method which helps with the 'getAllDiaryEntries' . Such methods are not related with Sping and MongoDB, we just use them to stay loyal to our initial tutorial scenario. Ok, we are almost done! we just need to add a couple of annotations to our POJO and change the autowired bean from DaoMock to our newly created DaoMongo. In the DiaryEntry POJO we specify the name of the collection for our documents (one object corresponds to a document in our collection) and also we specify that the 'entryId'  field will be our unique identification for each document which will be generated automatically. The updated class:
package com.tasosmartidis.rest_api_tutorial.data;

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

@Document(collection="entries") 
public class DiaryEntry {

    @Id
    private String entryId;
    private String entryTitle;
    private String entryText;
    
    public String getEntryId() {
        return entryId;
    }
    public void setEntryId(String entryId) {
        this.entryId = entryId;
    }
    public String getEntryTitle() {
        return entryTitle;
    }
    public void setEntryTitle(String entryTitle) {
        this.entryTitle = entryTitle;
    }
    public String getEntryText() {
        return entryText;
    }
    public void setEntryText(String entryText) {
        this.entryText = entryText;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((entryId == null) ? 0 : entryId.hashCode());
        result = prime * result
                + ((entryTitle == null) ? 0 : entryTitle.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DiaryEntry other = (DiaryEntry) obj;
        if (entryId == null) {
            if (other.entryId != null)
                return false;
        } else if (!entryId.equals(other.entryId))
            return false;
        if (entryTitle == null) {
            if (other.entryTitle != null)
                return false;
        } else if (!entryTitle.equals(other.entryTitle))
            return false;
        return true;
    }
    
}

Next our controller class, which exposes the REST API is almost unchanged, just use the DaoMongo instead of DaoMock:
package com.tasosmartidis.rest_api_tutorial.web;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.tasosmartidis.rest_api_tutorial.data.DaoMongo;
import com.tasosmartidis.rest_api_tutorial.data.DiaryEntry;

@RestController
@RequestMapping("/service/geek-diaries")
public class DiaryService {
    
    @Autowired
    DaoMongo dao; 
    
    @RequestMapping(value="/entry/{entryId}", method=RequestMethod.GET)
    public ResponseEntity<DiaryEntry> getDiaryEntry(@PathVariable String entryId) {
        DiaryEntry diaryEntry = dao.getDiaryEntry(entryId);
        
        return new ResponseEntity<DiaryEntry>(diaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/", method=RequestMethod.POST)
    public ResponseEntity<DiaryEntry> createDiaryEntry(@RequestBody DiaryEntry newEntry) { 
         DiaryEntry newDiaryEntry = dao.createDiaryEntry(newEntry);

        return new ResponseEntity<DiaryEntry>(newDiaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/", method=RequestMethod.PUT)
    public ResponseEntity<DiaryEntry> updateDiaryEntry(@RequestBody DiaryEntry newEntry) { 
         DiaryEntry updatedDiaryEntry = dao.updateDiaryEntry(newEntry);

        return new ResponseEntity<DiaryEntry>(updatedDiaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/{entryId}", method=RequestMethod.DELETE)
    public ResponseEntity<String> deleteDiaryEntry(@PathVariable String entryId) { 
         String deletedDiaryEntry = dao.deleteDiaryEntry(entryId);

        return new ResponseEntity<String>(deletedDiaryEntry,HttpStatus.OK); 
    }
    
    @RequestMapping(value="/entry/", method=RequestMethod.GET)
    public ResponseEntity<Map<String, DiaryEntry>> getDiaryEntries() { 
        Map<String, DiaryEntry> diaryEntries = dao.getAllDiaryEntries();

        return new ResponseEntity<Map<String, DiaryEntry>>(diaryEntries,HttpStatus.OK); 
    }
}

Don't you love it when software is properly designed and layered so that changes are easy to make? That's it! There is nothing else to change from our initial tutorial. As a brief recap, the maven was extended to include the new dependencies (i.e., spring data), an additional configuration class for connecting to MongoDB was created, the DaoMongo class for CRUD operations was defined and replaced DaoMock in the DiaryService controller.

Now let's see how the application works. We already started MongoDB, Tomcat and we deployed the packaged war. We will use POSTMAN to perform the CRUD operations. Let's start by creating a couple of diary entries using a POST operation:

and another one:

We can see the created entries from the MongDB shell as shown in the figure below:
and by calling the getAllEntries service which is a GET request:

Next we will retrieve a specific diary entry by indicating its unique ID in the URL of the GET request:
 Let's update one of our entries with a PUT operation:

 And conclude our CRUD operations with a DELETE request for a resource:

Let's see again in our MongoDB shell, the documents that exist in our collection:

And we are done! We extended our REST API to persist data in MongoDB using Spring Data. The complete working project is available on GitHub.