Create RESTful APIs using Spring Boot + Mongo DB
Tags: java, tutorial, mongodb, springboot
Published: 2019-12-30 15:36:25

##1. Overview

Nowadays, a web application is often separated into two components - frontend and backend.

With the growing popularity of frontend technologies like Angular and React, backend features are often exposed as the RESTful APIs.

In this tutorial, we'll create RESTful APIs using [Spring Boot](https://spring.io/projects/spring-boot). At the same time, we'll use [Spring Data MongoDB](https://spring.io/projects/spring-data-mongodb) to provide persistence support in our App by connecting to MongoDB.

##2. Prerequisites

We need a set of standard tools:

- Java 8 or later
- Build Tool (Maven or Gradle)
- IDE (IntelliJ or Eclipse)

We'll use a combination of Java 8, [Gradle](https://gradle.org/) and [IntelliJ](https://www.jetbrains.com/idea/) for our implementation.

To quickly create the Spring Boot application, we'll use [Spring Initializr](https://start.spring.io/). Also, we'll install and configure [Mongo DB](https://docs.mongodb.com/manual/installation/).

##3. Application

Let's create RESTful APIs for a user registration app. 
For simplicity, we'll just add features to perform CRUD (Create, Read, Update and Delete) operations.

Once the Spring Boot app is created, we'll create the *application.properties* file with MongoDB configuration details:

```text
spring.data.mongodb.database=springboot_mongo_db
```

###3.1. Entity

First, we'll create the *User* entity with basic properties like *firstName*, *lastName*, and *email*:

```java
@Getter
@Setter
public class User {
    @Id
    private String id;

    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private String address;
}
```

Here, we've used [*@Id*](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/annotation/Id.html) annotation to define the identifier.

At the same time, we've used [*@Getter*](https://projectlombok.org/api/lombok/Getter.html) and [*@Setter*](https://projectlombok.org/api/lombok/Setter.html) annotations provided by the [Project Lombok](https://objectcomputing.com/resources/publications/sett/january-2010-reducing-boilerplate-code-with-project-lombok) to create getters/setters automatically.

###3.2. Repository

Then, we'll create the *UserRepository* interface that provides basic operations on the database using Spring Data provided [*MongoRepository*](https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/repository/MongoRepository.html):

```java
public interface UserRepository extends MongoRepository<User, String> {
}
```

###3.3. Service

Next, we'll create a service class that provides the business logic for basic CRUD operations. 

For this, let's create the *Registration* interface to define the abstraction:

```java
public interface Registration<ID, USER> {
    USER registerUser(USER user) throws Exception;

    USER getUser(ID userId) throws Exception;

    USER updateUser(USER user) throws Exception;

    void deleteUser(ID userId) throws Exception;
}
```

Then, we'll create the *RegistrationImpl* class to implement the *Registration* interface:

```java
@Service
public class RegistrationImpl implements Registration<String, User> {
    @Autowired
    private UserRepository userRepository;

    @Override
    public User registerUser(User user) throws Exception {
        user = userRepository.save(user);
        return user;
    }

    @Override
    public User getUser(String userId) throws Exception {
        User user = userRepository.findById(userId);
        return user;
    }

    public List<User> getAllUser() throws Exception {
        List<User> users = userRepository.findAll();
        return users;
    }

    @Override
    public User updateUser(User user) throws Exception {
        user = userRepository.save(user);
        return user;
    }

    @Override
    public void deleteUser(String userId) throws Exception {
        if (userId == null) {
            throw new Exception("user id is null");
        } else {
            userRepository.delete(userId);
        }
    }
}
```

Note that we've used [*@Service*](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/stereotype/Service.html) annotation to declare the *RegistrationImpl* class as a service for Spring Boot. Also, we've used [*@Autowired*](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html) annotation to inject the *UserRepository* dependency.

###3.4. Controller

Now that we've got entity, repository and service ready, we'll create the *RegistrationController* class to expose the APIs:

```java
@RestController
public class RegistrationController {
    @Autowired
    private RegistrationImpl registrationImpl;
}
```

Here, we've used [*@RestController*](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html) annotation to declare it as a RESTful API controller.

At first, we'll add a method *registerUser* to register the user (CREATE):

```java
@PostMapping(path = "/registerUser")
public ResponseEntity registerUser(@RequestBody User user) throws Exception {
    HashMap<String, Object> resp = new HashMap<>();
    registrationImpl.registerUser(user);
    resp.put("user", user);
    return new ResponseEntity<>(resp, HttpStatus.OK);
}
```

Voila, we're ready with our first RESTful API to register the user.

Let's try it using the following curl command:

```shell
curl -X POST "http://localhost:8080/registerUser" -H "Content-Type: application/json" \
-d '{"email": "xyz@email.com", "firstName": "norman", "lastName": "lewis", "phone": "90909090"}'

```

Then, let's add a method *getUser* to search the user by id (READ):

```java
@GetMapping("/getUser" )
public ResponseEntity getUser(@RequestParam("id") String id) throws Exception {
    User user = registrationImpl.getUser(id);
    return new ResponseEntity<>(user, HttpStatus.OK);
}
```

So, we can use the curl to read the user:

```shell
curl -X GET "http://localhost:8080/getUser?id=5e0a0a393844b64a1548c4d9"
```

Similarly, we can define a method *getAllUser* to fetch all the users:

```java
@GetMapping("/getAllUser" )
public ResponseEntity getAllUser() throws Exception {
    List<User> users = registrationImpl.getAllUser();
    return new ResponseEntity<>(users, HttpStatus.OK);
}
```

Then, we'll add a method *updateUser* to update the user (UPDATE):

```java
@PutMapping(path = "/updateUser")
public ResponseEntity updateUser(@RequestParam("id") String id, @RequestBody User user) 
throws Exception {
    HashMap<String, Object> resp = new HashMap<>();
    registrationImpl.updateUser(user);
    resp.put("user", user);
    return new ResponseEntity<>(resp, HttpStatus.OK);
}
```

Last, let's add a method *deleteUser* to delete the user (DELETE):

```java
@DeleteMapping("/deleteUser")
public ResponseEntity deleteUser(@RequestParam("id") String id) throws Exception {
    registrationImpl.deleteUser(id);
    HashMap<String,String> resp = new HashMap<>();
    resp.put("message", "User is successfully deleted");
    return new ResponseEntity<>(resp, HttpStatus.OK);
}
```

###3.5. Validation

Next, we'll add the feature of bean validations to our APIs using [*hibernate-validator*](https://hibernate.org/validator/).

First, we'll add the dependency to the *build.gradle*:

```groovy
compile group: 'org.hibernate', name: 'hibernate-validator', version: '5.0.0.Final'
```

Then, we'll add a few annotations like [*@NotNull*](https://docs.oracle.com/javaee/7/api/javax/validation/constraints/NotNull.html) and [*@Email*](https://docs.jboss.org/hibernate/validator/6.0/api/index.html?org/hibernate/validator/constraints/Email.html) to the *User* entity.

```java
public class User {
    // ...

    @NotNull(message = "First Name is mandatory")
    private String firstName;

    @NotNull(message = "Last Name is mandatory")
    private String lastName;

    @NotNull(message = "Email is mandatory")
    @Email(message = "Not valid email")
    @Indexed(unique=true)
    private String email;

    @NotNull(message = "Phone Number is mandatory")
    private String phone;    
}
```

Next, we'll use the [*ValidatingMongoEventListener*](https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/mapping/event/ValidatingMongoEventListener.html) to register as a bean in the main class - *Application*:

```java
@SpringBootApplication
public class Application {
    @Bean
    public ValidatingMongoEventListener validatingMongoEventListener() {
        return new ValidatingMongoEventListener(validator());
    }

    @Bean
    public LocalValidatorFactoryBean validator() {
        return new LocalValidatorFactoryBean();
    }

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

Last, we'll modify the *registerUser* method in the *RegistrationController* to validate the User object:

```java
@PostMapping(path = "/registerUser")
public ResponseEntity registerUser(@RequestBody User user) throws Exception {
    HashMap<String, Object> resp = new HashMap<>();
    try {
        registrationImpl.registerUser(user);
    } catch (ConstraintViolationException e) {
        HashMap<String, String> messages = new HashMap<>();
        e.getConstraintViolations().stream().forEach(constraintViolation -> {
            messages.put(
                    constraintViolation.getPropertyPath().toString(),
                    constraintViolation.getMessage());
        });
        resp.put("error", true);
        resp.put("messages", messages);
    }
    resp.put("user", user);
    return new ResponseEntity<>(resp, HttpStatus.OK);
}
```

That's it! We're ready to examine the validation:

```shell
curl -X POST "http://localhost:8080/registerUser" -H "Content-Type: application/json" -d '{"email": "xyz@email.com"}'
```

Here, we've not provided *firstName*, *lastName*, and *phone*. So, the response will be:

```shell
{"messages":{"firstName":"First Name is mandatory","lastName":"Last Name is mandatory","phone":"Phone Number is mandatory"},"error":true,"user":{"id":null,"firstName":null,"lastName":null,"email":"xyz12@email.com","phone":null,"address":null}}
```

###3.6. Swagger Integration

So far, we've used curl to request our APIs. Now, we'll integrate [Swagger 2 documentation for our APIs](https://dev.to/smartyansh/introduction-to-springfox-48ng) using Springfox.

All we need is to add the Springfox dependencies in *build.gradle*:

```groovy
compile "io.springfox:springfox-swagger2:2.9.2"
compile 'io.springfox:springfox-swagger-ui:2.9.2'
```

Then, we'll annotate the main class with @EnableSwagger2 annotation:

```java
@EnableSwagger2
@SpringBootApplication
public class Application {

    // ...
}
```

That's it! Our API specifications are ready and are accessible at *http://localhost:8080/swagger-ui.html*.

##4. Conclusion

In this tutorial, we've created RESTful APIs for the User registration App using SpringBoot and Spring Data Mongo DB.
Also, we've used Project Lombok to reduce the boiler-plate code and Springfox APIs for Swagger 2 documentation.

The entire code implementations are available over on [Github](https://github.com/SmartyAnsh/springboot_mongo)

Please let me know your thoughts on it!
Thanks for reading.