Creating a REST API With Spring Boot and MongoDB

This year I greeted Christmas in a different fashion: I was a part of the Java Advent Calendar. Let's boot up for Christmas:

Spring Boot is an opinionated framework that simplifies the development of Spring applications. It frees us from the slavery of complex configuration files and helps us to create standalone Spring applications that don’t need an external servlet container.

This sounds almost too good to be true, but Spring Boot can really do all this.

This blog post demonstrates how easy it is to implement a REST API that provides CRUD operations for todo entries that are saved to MongoDB database.

Let’s start by creating our Maven project.

This blog post assumes that you have already installed the MongoDB database. If you haven’t done this, you can follow the instructions given in the blog post titled: Accessing Data with MongoDB.

Creating Our Maven Project

We can create our Maven project by following these steps:

  1. Use the spring-boot-starter-parent POM as the parent POM of our Maven project. This ensures that our project inherits sensible default settings from Spring Boot.
  2. Add the Spring Boot Maven Plugin to our project. This plugin allows us to package our application into an executable jar file, package it into a war archive, and run the application.
  3. Configure the dependencies of our project. We need to configure the following dependencies:
    • The spring-boot-starter-web dependency provides the dependencies of a web application.
    • The spring-data-mongodb dependency provides integration with the MongoDB document database.
  4. Enable the Java 8 Support of Spring Boot.
  5. Configure the main class of our application. This class is responsible of configuring and starting our application.

The relevant part of our pom.xml file looks as follows:

<properties>
    <!-- Enable Java 8 -->
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <!-- Configure the main class of our Spring Boot application -->
    <start-class>com.javaadvent.bootrest.TodoAppConfig</start-class>
</properties>
        
<!-- Inherit defaults from Spring Boot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.1.9.RELEASE</version>
</parent>

<dependencies>
    <!-- Get the dependencies of a web application -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Data MongoDB-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-mongodb</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!-- Spring Boot Maven Support -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Let’s move on and find out how we can configure our application.

Configuring Our Application

We can configure our Spring Boot application by following these steps:

  1. Create a TodoAppConfig class to the com.javaadvent.bootrest package.
  2. Enable Spring Boot auto-configuration.
  3. Configure the Spring container to scan components found from the child packages of the com.javaadvent.bootrest package.
  4. Add the main() method to the TodoAppConfig class and implement by running our application.

The source code of the TodoAppConfig class looks as follows:

package com.javaadvent.bootrest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class TodoAppConfig {
    
    public static void main(String[] args) {
        SpringApplication.run(TodoAppConfig.class, args);
    }
}

We have now created the configuration class that configures and runs our Spring Boot application. Because the MongoDB jars are found from the classpath, Spring Boot configures the MongoDB connection by using its default settings.

Let’s move on and implement our REST API.

Implementing Our REST API

We need implement a REST API that provides CRUD operations for todo entries. The requirements of our REST API are:

  • A POST request send to the url ‘/api/todo’ must create a new todo entry by using the information found from the request body and return the information of the created todo entry.
  • A DELETE request send to the url ‘/api/todo/{id}’ must delete the todo entry whose id is found from the url and return the information of the deleted todo entry.
  • A GET request send to the url ‘/api/todo’ must return all todo entries that are found from the database.
  • A GET request send to the url ‘/api/todo/{id}’ must return the information of the todo entry whose id is found from the url.
  • A PUT request send to the url ‘/api/todo/{id}’ must update the information of an existing todo entry by using the information found from the request body and return the information of the updated todo entry.

We can fulfill these requirements by following these steps:

  1. Create the entity that contains the information of a single todo entry.
  2. Create the repository that is used to save todo entries to MongoDB database and find todo entries from it.
  3. Create the service layer that is responsible of mapping DTOs into domain objects and vice versa. The purpose of our service layer is to isolate our domain model from the web layer.
  4. Create the controller class that processes HTTP requests and returns the correct response back to the client.
This example is so simple that we could just inject our repository to our controller. However, because this is not a viable strategy when we are implementing real-life applications, we will add a service layer between the web and repository layers.

Let’s get started.

Creating the Entity

We need to create the entity class that contains the information of a single todo entry. We can do this by following these steps:

  1. Add the id, description, and title fields to the created entity class. Configure the id field of the entity by annotating the id field with the @Id annotation.
  2. Specify the constants (MAX_LENGTH_DESCRIPTION and MAX_LENGTH_TITLE) that specify the maximum length of the description and title fields.
  3. Add a static builder class to the entity class. This class is used to create new Todo objects.
  4. Add an update() method to the entity class. This method simply updates the title and description of the entity if valid values are given as method parameters.

The source code of the Todo class looks as follows:

import org.springframework.data.annotation.Id;

import static com.javaadvent.bootrest.util.PreCondition.isTrue;
import static com.javaadvent.bootrest.util.PreCondition.notEmpty;
import static com.javaadvent.bootrest.util.PreCondition.notNull;

final class Todo {

    static final int MAX_LENGTH_DESCRIPTION = 500;
    static final int MAX_LENGTH_TITLE = 100;

    @Id
    private String id;

    private String description;

    private String title;

    public Todo() {}

    private Todo(Builder builder) {
        this.description = builder.description;
        this.title = builder.title;
    }

    static Builder getBuilder() {
        return new Builder();
    }

    //Other getters are omitted

    public void update(String title, String description) {
        checkTitleAndDescription(title, description);

        this.title = title;
        this.description = description;
    }

    /**
     * We don't have to use the builder pattern here because the constructed 
     * class has only two String fields. However, I use the builder pattern 
     * in this example because it makes the code a bit easier to read.
     */
    static class Builder {

        private String description;

        private String title;

        private Builder() {}

        Builder description(String description) {
            this.description = description;
            return this;
        }

        Builder title(String title) {
            this.title = title;
            return this;
        }

        Todo build() {
            Todo build = new Todo(this);

            build.checkTitleAndDescription(build.getTitle(), build.getDescription());

            return build;
        }
    }

    private void checkTitleAndDescription(String title, String description) {
        notNull(title, "Title cannot be null");
        notEmpty(title, "Title cannot be empty");
        isTrue(title.length() <= MAX_LENGTH_TITLE,
                "Title cannot be longer than %d characters",
                MAX_LENGTH_TITLE
        );

        if (description != null) {
            isTrue(description.length() <= MAX_LENGTH_DESCRIPTION,
                    "Description cannot be longer than %d characters",
                    MAX_LENGTH_DESCRIPTION
            );
        }
    }
}

Let's move on and create the repository that communicates with the MongoDB database.

Creating the Repository

We have to create the repository interface that is used to save Todo objects to MondoDB database and retrieve Todo objects from it.

If we don’t want to use the Java 8 support of Spring Data, we could create our repository by creating an interface that extends the CrudRepository<T, ID> interface. However, because we want to use the Java 8 support, we have to follow these steps:

  1. Create an interface that extends the Repository<T, ID> interface.
  2. Add the following repository methods to the created interface:
    1. The void delete(Todo deleted) method deletes the todo entry that is given as a method parameter.
    2. The List findAll() method returns all todo entries that are found from the database.
    3. The Optional findOne(String id) method returns the information of a single todo entry. If no todo entry is found, this method returns an empty Optional.
    4. The Todo save(Todo saved) method saves a new todo entry to the database and returns the the saved todo entry.

The source code of the TodoRepository interface looks as follows:

import org.springframework.data.repository.Repository;

import java.util.List;
import java.util.Optional;

interface TodoRepository extends Repository<Todo, String> {

    void delete(Todo deleted);

    List<Todo> findAll();

    Optional<Todo> findOne(String id);

    Todo save(Todo saved);
}

Let’s move on and create the service layer of our example application.

Creating the Service Layer

First, we have to create a service interface that provides CRUD operations for todo entries. The source code of the TodoService interface looks as follows:

import java.util.List;

interface TodoService {

    TodoDTO create(TodoDTO todo);

    TodoDTO delete(String id);

    List<TodoDTO> findAll();

    TodoDTO findById(String id);

    TodoDTO update(TodoDTO todo);
}
The TodoDTO class is a DTO that contains the information of a single todo entry. We will talk more about it when we create the web layer of our example application.

Second, we have to implement the TodoService interface. We can do this by following these steps:

  1. Inject our repository to the service class by using constructor injection.
  2. Add a private Todo findTodoById(String id) method to the service class and implement it by either returning the found Todo object or throwing the TodoNotFoundException.
  3. Add a private TodoDTO convertToDTO(Todo model) method the service class and implement it by converting the Todo object into a TodoDTO object and returning the created object.
  4. Add a private List convertToDTOs(List models) and implement it by converting the list of Todo objects into a list of TodoDTO objects and returning the created list.
  5. Implement the TodoDTO create(TodoDTO todo) method. This method creates a new Todo object, saves the created object to the MongoDB database, and returns the information of the created todo entry.
  6. Implement the TodoDTO delete(String id) method. This method finds the deleted Todo object, deletes it, and returns the information of the deleted todo entry. If no Todo object is found with the given id, this method throws the TodoNotFoundException.
  7. Implement the List findAll() method. This methods retrieves all Todo objects from the database, transforms them into a list of TodoDTO objects, and returns the created list.
  8. Implement the TodoDTO findById(String id) method. This method finds the Todo object from the database, converts it into a TodoDTO object, and returns the created TodoDTO object. If no todo entry is found, this method throws the TodoNotFoundException.
  9. Implement the TodoDTO update(TodoDTO todo) method. This method finds the updated Todo object from the database, updates its title and description, saves it, and returns the updated information. If the updated Todo object is not found, this method throws the TodoNotFoundException.

The source code of the MongoDBTodoService looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

import static java.util.stream.Collectors.toList;

@Service
final class MongoDBTodoService implements TodoService {

    private final TodoRepository repository;

    @Autowired
    MongoDBTodoService(TodoRepository repository) {
        this.repository = repository;
    }

    @Override
    public TodoDTO create(TodoDTO todo) {
        Todo persisted = Todo.getBuilder()
                .title(todo.getTitle())
                .description(todo.getDescription())
                .build();
        persisted = repository.save(persisted);
        return convertToDTO(persisted);
    }

    @Override
    public TodoDTO delete(String id) {
        Todo deleted = findTodoById(id);
        repository.delete(deleted);
        return convertToDTO(deleted);
    }

    @Override
    public List<TodoDTO> findAll() {
        List<Todo> todoEntries = repository.findAll();
        return convertToDTOs(todoEntries);
    }

    private List<TodoDTO> convertToDTOs(List<Todo> models) {
        return models.stream()
                .map(this::convertToDTO)
                .collect(toList());
    }

    @Override
    public TodoDTO findById(String id) {
        Todo found = findTodoById(id);
        return convertToDTO(found);
    }

    @Override
    public TodoDTO update(TodoDTO todo) {
        Todo updated = findTodoById(todo.getId());
        updated.update(todo.getTitle(), todo.getDescription());
        updated = repository.save(updated);
        return convertToDTO(updated);
    }

    private Todo findTodoById(String id) {
        Optional<Todo> result = repository.findOne(id);
        return result.orElseThrow(() -> new TodoNotFoundException(id));

    }

    private TodoDTO convertToDTO(Todo model) {
        TodoDTO dto = new TodoDTO();

        dto.setId(model.getId());
        dto.setTitle(model.getTitle());
        dto.setDescription(model.getDescription());

        return dto;
    }
}

We have now created the service layer of our example application. Let's move on and create the controller class.

Creating the Controller Class

First, we need to create the DTO class that contains the information of a single todo entry and specifies the validation rules that are used to ensure that only valid information can be saved to the database. The source code of the TodoDTO class looks as follows:

import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.constraints.Size;

public final class TodoDTO {

    private String id;

    @Size(max = Todo.MAX_LENGTH_DESCRIPTION)
    private String description;

    @NotEmpty
    @Size(max = Todo.MAX_LENGTH_TITLE)
    private String title;

    //Constructor, getters, and setters are omitted
}

Second, we have to create the controller class that processes the HTTP requests send to our REST API and sends the correct response back to the client. We can do this by following these steps:

  1. Inject our service to our controller by using constructor injection.
  2. Add a create() method to our controller and implement it by following these steps:
    1. Read the information of the created todo entry from the request body.
    2. Validate the information of the created todo entry.
    3. Create a new todo entry and return the created todo entry. Set the response status to 201.
  3. Implement the delete() method by delegating the id of the deleted todo entry forward to our service and return the deleted todo entry.
  4. Implement the findAll() method by finding the todo entries from the database and returning the found todo entries.
  5. Implement the findById() method by finding the todo entry from the database and returning the found todo entry.
  6. Implement the update() method by following these steps:
    1. Read the information of the updated todo entry from the request body.
    2. Validate the information of the updated todo entry.
    3. Update the information of the todo entry and return the updated todo entry.
  7. Create an @ExceptionHandler method that sets the response status to 404 if the todo entry was not found (TodoNotFoundException was thrown).

The source code of the TodoController class looks as follows:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("/api/todo")
final class TodoController {

    private final TodoService service;

    @Autowired
    TodoController(TodoService service) {
        this.service = service;
    }

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    TodoDTO create(@RequestBody @Valid TodoDTO todoEntry) {
        return service.create(todoEntry);
    }

    @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
    TodoDTO delete(@PathVariable("id") String id) {
        return service.delete(id);
    }

    @RequestMapping(method = RequestMethod.GET)
    List<TodoDTO> findAll() {
        return service.findAll();
    }

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    TodoDTO findById(@PathVariable("id") String id) {
        return service.findById(id);
    }

    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    TodoDTO update(@RequestBody @Valid TodoDTO todoEntry) {
        return service.update(todoEntry);
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public void handleTodoNotFound(TodoNotFoundException ex) {
    }
}
If the validation fails, our REST API returns the validation errors as JSON and sets the response status to 400. If you want to know more about this, read a blog post titled: Spring from the Trenches: Adding Validation to a REST API.

That is it. We have now created a REST API that provides CRUD operations for todo entries and saves them to MongoDB database. Let’s summarize what we learned from this blog post.

Summary

This blog post has taught us three things:

  • We can get the required dependencies with Maven by declaring only two dependencies: spring-boot-starter-web and spring-data-mongodb.
  • If we are happy with the default configuration of Spring Boot, we can configure our web application by using its auto-configuration support and “dropping” new jars to the classpath.
  • We learned to create a simple REST API that saves information to MongoDB database and finds information from it.

P.S. You can get the example application of this blog post from Github.

This post is part of the Java Advent Calendar and is licensed under the Creative Commons 3.0 Attribution license.

Read the original blog post: Creating a REST API with Spring Boot and MongoDB.

76 comments… add one
  • David Kiss Dec 29, 2014 @ 16:37

    Thanks for the post. Very nice and elegant code! I like the idea of using the builder pattern with the entity object and also using the streaming api when converting from entity list to DTO list.

    You may consider using the @RepositoryRestResource annotation that instructs Spring to expose REST endpoints for repository operations. Here's an example on how to use it: http://kaviddiss.com/2014/12/28/twitter-feed-using-spring-boot

    • Petri Dec 29, 2014 @ 18:49

      Thank you for your kind words. I really appreciate them!

      Also, thank you for reminding me about Spring Data REST. We tried it very briefly when its first versions were released, but at the time we decided not to use it.

      I am updating my Spring Data JPA tutorial, and Spring Data REST tutorial would be a good addition to my Spring Data tutorials -> Now is a good time to give it a second chance.

      • David Kiss Dec 30, 2014 @ 5:14

        Glad to hear that. I'd be definitely interested in a Spring Data REST tutorial!

      • Kaushlesh Pandey Apr 20, 2020 @ 13:55

        How to save data into the relationship table using the controller in Spring boot ?

  • Vin Dec 31, 2014 @ 14:37

    Thank you writing this tutorial. It is very well written and clears many of my questions in this context.

    Can you please explain why do you recommend using a DTO instead of directly using model objects?. I am sure there must be a reason.

    Also if you could keep the pseudo code and the actual code side by side, it would be much more enjoyable experience (IMO) to read.

    • Petri Dec 31, 2014 @ 15:05

      Can you please explain why do you recommend using a DTO instead of directly using model objects?. I am sure there must be a reason.

      There are two reasons why I think that returning DTOs is a good idea:

      1. The domain model specifies the internal model of our application. If we expose this model to the outside world, the clients would have to know how to use it. In other words, the clients of our application would have to take care of things that don’t belong to them. If we use DTOs, we can hide this model from the clients of our application, and provide an easier and cleaner API.
      2. If we expose our domain model to the outside world, we cannot change it without breaking the other stuff that depends from it. If we use DTOs, we can change our domain model as long as we don’t make any changes to the DTOs.

      If you are interested in this subject, you might want to read this blog post. It introduces the "classic" architecture of a Spring web application, and it might give you some new ideas. However, it is good to understand that the classic way is not the best way anymore (IMO).

      Also if you could keep the pseudo code and the actual code side by side, it would be much more enjoyable experience (IMO) to read.

      I agree. The problem is that I haven't found a Wordpress plugin that would support this. :(

  • Andreas May 7, 2015 @ 11:49

    No Tests?

    • Petri May 7, 2015 @ 12:42

      The example application has unit tests. However, it doesn't have integration tests since I didn't have time to figure out how to write integration tests that use MongoDB database.

      • Lukasz May 14, 2015 @ 21:14

        It would be extremely useful if you added integration tests.

        • Petri May 15, 2015 @ 19:38

          I added a new card to my Trello board since it seems that these tests are useful to you. I will update one of my older blog posts before I will take a closer look at this. If everything goes as expected, I assume that I can write those tests next weekend.

          • Kane Jun 4, 2015 @ 13:18

            Petri, thanks for your nice work! It would be great to have integration test example as well.

          • Petri Jun 4, 2015 @ 18:47

            I will try to write some integration tests next weekend. I was supposed to write them a bit earlier, but I didn't have time to do it because I was busy updating my Spring Data JPA tutorial.

  • Kane Jun 4, 2015 @ 13:16

    I'm following this guide to implement my web app.
    In my app I throw PropertyNotFoundException when the prop can not be found in mongodb with given id. I also expect there is 404 response to the client. However I got below exception instead of 404 response,

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.devicehub.api.exception.PropertyNotFoundException: No property found with id:
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:144)
    at

    Do you have any idea for this?

    Thank you.

    Update: I removed the irrelevant part from the stacktrace - Petri

    • Petri Jun 4, 2015 @ 18:43

      Hi,

      Check out the source code of the TodoController class. The handleTodoNotFound() method returns the 404 HTTP status code when the TodoNotFoundException is thrown. I think that you can use the same approach in your application.

      Also, if the PropertyNotFoundException exception is thrown by more than one class, it is often a good idea to move the @ExceptionHandler method to a class that is annotated with the @ControllerAdvice annotation.

      If you have any further questions about this, don't hesitate to ask them.

      • Kane Jun 5, 2015 @ 5:03

        Petri, thanks for the hint.

        • Petri Jun 5, 2015 @ 21:45

          You are welcome.

  • Nagendra Jun 23, 2015 @ 6:10

    Where are we writing DB connection in this project?

    • Petri Jun 23, 2015 @ 9:48

      We are not writing directly to the MongoDB connection. This example application follows these steps:

      1. It creates a MongoDB connection by using Spring Boot's default settings (See Spring Boot Reference Manual: 29.2.1 Connecting to a MongoDB database for more details).
      2. It saves information to MongoDB database and finds information from it by using Spring Data MongoDB.

      I hope that this answered to your question. If you have any additional questions, don't hesitate to ask them!

      • Shyam Jun 25, 2015 @ 12:44

        Thanks..! I had the same doubt.

        • Petri Jun 25, 2015 @ 13:12

          You are welcome!

  • Kreg Jun 25, 2015 @ 12:53

    I am bit new to technical field. I want to know from where I have to run this project? I mean which class I have to run ?

    • Petri Jun 25, 2015 @ 13:10

      Hi Kreg,

      you can get the example application from Github. You can either clone the Git repository or download the source code as Zip file (click the Download ZIP link).

      Before you can run the application, you need to

      1. Install Java 8 SDK
      2. Download and install Maven
      3. Install MongoDB

      After you have installed Java 8 SDK, Maven, and MongoDB, you can run the application by running the command: mvn clean spring-boot:run at command prompt.

      If you have any further questions, don't hesitate to ask them.

      • Kreg Jun 26, 2015 @ 14:07

        Thanks a lot Petri ! Much appreciated your talent.

        • Petri Jun 26, 2015 @ 23:15

          You are welcome!

  • Joe Gaber Jul 26, 2015 @ 7:33

    Answered my own question. I've never seen an update method in a domain object before so I missed it in the example. It didn't make sense to me so I spaced it out. Can you explain why you do that?

    • Petri Jul 26, 2015 @ 15:46

      Well, basically the update(String title, String description) method is just a "setter" method that has more than one parameter.

      I use these methods because they help me to create "atomic" update operations. Each update method updates the field values of fields that belong to the same "logical" group. Also, these methods guarantee that the new field values of the updated fields are valid or they throw an exception.

      If I would use traditional setter methods, my service methods would have to invoke multiple setter methods. This means that they would a be lot messier than the service methods that simply invoke these update methods.

      However, if the updated object has too many properties, it is not practical to have just one update method. In these cases I create methods such as: updateInvoicingAddress(), updateMailingAddress(), and so on.

      • Anonymous Jul 29, 2015 @ 4:37

        excellent ideas, thanks.

        • Petri Jul 29, 2015 @ 14:07

          You are welcome!

          Just remember to use common sense. Sometimes using these update methods makes sense, but sometimes a simple setter method is the best tool for the job. It all depends from your requirements.

  • Js Aug 5, 2015 @ 2:20

    Could you give an example of a CRUD operation, for example POST, because I'm not sure how to make it work.

    • Petri Aug 5, 2015 @ 10:25

      Do you mean that you don't know how you can create HTTP requests (like POST for example) that are processed by the controller methods? If so, are you using jQuery, AngularJS, or some other JS framework?

      • Js Aug 5, 2015 @ 16:09

        Yes.
        I'm not using any of these, I just wanted to check how it works using a browser.

        • Js Aug 5, 2015 @ 16:13

          I mean, using mozilla extension.

          • Petri Aug 6, 2015 @ 9:28

            I use RESTClient for this purpose. You can create a POST request by following these steps:

            • Select the invoked method (POST) by using the 'Method' combo box.
            • Set the request url to the 'URL' text field. For example, if you run your application in localhost, you can use the url localhost:8080/api/todo (remember to add the prefix: http://).
            • Create a request header called Content-Type and set its value to application/json (You can find the correct popup from Headers -> Custom Header).
            • Add the information of the created todo entry to the request body as json.

            If you want create a todo entry whose title is 'foo' and description is 'bar', you can use the following json:

            
            {
            	"title": "foo",
            	"description": "bar"
            }
            
            

            I hope that this answered to your question.

  • Krishna Oct 16, 2015 @ 8:25

    Except MongoDb configuration , you have mentioned everything.

  • Shreejit Dec 9, 2015 @ 3:44

    Hi Petri,

    Is there a way to know which database my java application is pointing to.
    I basically want to find all the documents across all collections that has been loaded in the database.
    I am expecting some get expressions to execute correctly say get(/templates/json/names) but i am unable to understand what exactly the expression means here. Does it mean collection name is templates? and remaining uri is the further xpath expression. For some reason my data is coming as blank for the uri expressions and i am trying to diagnose why my documents are not getting retrieved.

    Thanks
    Shreejit

    • Petri Dec 9, 2015 @ 22:46

      Hi Shreejit,

      I have used MongoDb only once when I wrote this blog post. Unfortunately this means that I don't know the answer to your question :( Have you tried posting it to StackOverflow?

  • Goran Mar 1, 2016 @ 19:00

    Hi Petri,

    Correct me if I am wrong but your update method does not take into account id from url?
    So if I PUT /api/todo/mickeyMouse with body {id:"1", title:"My Todo"} it will update todo with id 1 and ignore "mickeyMouse" from the url?

    Cheers,
    Goran

    • Petri Mar 1, 2016 @ 20:13

      Hi Goran,

      you are right.

      • Goran Mar 2, 2016 @ 10:01

        Hi Petri,

        I was hoping for more details :)
        Is it something expected or is it something that you would want to fix? I saw the similar implementation in book "Spring REST", without dtos but still ignoring id from url.
        Is there maybe some spring magic that would shove that id in the request bodu object?

        Cheers,
        Goran.

        • Petri Mar 3, 2016 @ 19:16

          Hi Goran,

          I was hoping for more details :)

          Ah. Sorry about that. I was in Finnish mode which means that I answer only to the question that was asked :P

          Is it something expected or is it something that you would want to fix? I saw the similar implementation in book “Spring REST”, without dtos but still ignoring id from url.

          Well, there are two things to consider here:

          • If you want to implement a "real" REST API, you probably shouldn't ignore the id because the id identifies the updated resource. The "downside" of this approach is that you have to set the id to the DTO manually (I am not aware of a magic word that would do this for you).
          • If you want to be "pragmatic", you can ignore the id (especially if you use AngularJS that sends the id in the request body anyway). The problem of this approach is that you can send a request with an id 5 and update the entity whose id is 2. This is definitely confusing.

          In other words, if I would write this example now, I would not ignore the id found from the url.

  • Hm Mar 5, 2016 @ 19:28

    Hello petri,

    thank you for your toturial , I am new in Spring and have some question . i am sure that your answer as a professional can help me so much.

    would you please let me know your email to ask my question there ? looking forward to hear from you.

    thank you

    • Petri Mar 5, 2016 @ 21:24

      Sure. Let's continue this discussion via email.

  • Anne Racel Apr 27, 2016 @ 23:20

    I seem to have missed something in the implementation. I'm getting a NoSuchBeanDefinitionException:

    java.lang.IllegalStateException: Failed to load ApplicationContext
    ...
    ...
    Caused by org.springframework.beans.factory.UnsatisfiedDepenencyException: Error creating bean with name 'MongoDbToDoService' defined in file ['/home/anne/workspace-sts/SpringTraining/target/classes/MongoDbToDoService.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [ToDoRepository]: No qualifying bean of type [ToDoRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {};
    .....
    ....
    Caused by: org.springfamework.beans.bactory.NoSuchBeanDefinitionException: No qualifying bean of type [TodoRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

    • Petri Apr 28, 2016 @ 20:59

      Hi,

      It seems that for some reason Spring Boot could not find the TodoRepository bean. Did you remember to declare the spring-data-mongodb dependency in your POM file? Also, you should check that your application class is annotated with the @ComponentScan annotation.

  • Khoeurn Rotha Jun 17, 2016 @ 9:59

    Hello Petri,

    Thanks you for your nice tutorials. I am new in Spring and Mongodb. I want to insert jSON object into Mongodb collection that we didn't know its specific fields. I tried many way, but it didn't work for me. Could you please explain me how to do it? I am waiting to hear from you.

    Thanks you,

  • Mira Aug 9, 2016 @ 18:26

    Hi, i do not understand, can you tell me why to use the interfaces ToDoRepository and ToDoService? Why isn't it possible to put ToDoService in ToDoRepository? Thank you alot for this great tutorial!

    • Petri Aug 9, 2016 @ 21:17

      Hi,

      can you tell me why to use the interfaces ToDoRepository and ToDoService?

      The TodoRepository interface is a repository interface that is required by Spring Data MongoDB. In other words, you need to use that interface when you save information to your MongoDB database or query information from it.

      The TodoService interface declares the service API that provides CRUD operations for todo entries. Note that you don't necessarily have to create this interface if you have only implementation for it. If this is the case, you can create a service class and inject it to the controller.

      Why isn’t it possible to put ToDoService in ToDoRepository

      I didn't understand this question. Did you mean to ask: is it possible to inject TodoRepository to the TodoController?

  • sunny Aug 9, 2016 @ 18:42

    Hi Petri,
    I am getting this error when i try running the project which i created using spring tool suite
    i am not sure what the problem is

    2016-08-09 11:41:37.346 ERROR 10904 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.IllegalAccessError: tried to access class com.example.entity.Todo from class com.sun.proxy.$Proxy56] with root cause

    java.lang.IllegalAccessError: tried to access class com.example.entity.Todo from class com.sun.proxy.$Proxy56
    at com.sun.proxy.$Proxy56.save(Unknown Source) ~[na:na]
    at com.example.entity.MongoDBTodoService.create(MongoDBTodoService.java:27) ~[classes/:na]
    at com.example.entity.TodoController.create(TodoController.java:31) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_51]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_51]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_51]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_51]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)

    Update: I removed the irrelevant part of the stack trace - Petri

    • Petri Aug 9, 2016 @ 21:21

      Hi,

      Unfortunately I have never seen this exception. In fact, it looks so weird that it might be a version mismatch problem. Are you using the latest Spring and Spring Data MongoDB versions?

      • sunny Aug 9, 2016 @ 21:59

        i am using spring tool suite and it gave me option to select web and mongodb.this is pom file

        4.0.0

        com.ioc
        demo
        0.0.1-SNAPSHOT
        jar

        internetOfThings
        Demo project for Spring Boot

        org.springframework.boot
        spring-boot-starter-parent
        1.4.0.RELEASE

        UTF-8
        UTF-8
        1.8

        org.springframework.boot
        spring-boot-starter-data-mongodb

        org.springframework.boot
        spring-boot-starter-web

        org.springframework.boot
        spring-boot-starter-test
        test

        org.springframework.boot
        spring-boot-maven-plugin

        can we please communicate using email..i have the project due tomorrow..please

        • Petri Aug 9, 2016 @ 22:57

          The Spring Boot 1.4.0 uses MongoDB Driver 3.2.2. I took a quick look at its documentation and it looks like that this driver is compatible only with MongoDB 3.2.x. If you are using some other MongoDB version, you should either update your MongoDB version or use an older driver.

          I have to admit that I have no idea if this fixes your problem since I have no real-life experience from MongoDB (or Spring Data MongoDB). I simply wrote this blog post because I wanted to try it out.

      • kiran May 23, 2017 @ 12:51

        [ERROR] COMPILATION ERROR :
        [INFO] -------------------------------------------------------------
        [ERROR] /C:/Users/Kiran Pasuluri/Documents/SystemLogic/workspace/java-advent-2014/src/test/java/com/javaadvent/bootrest/todo/MongoDbTodoServiceTest.java:[28,8] class MongoDBTodoServiceTest is public, should be declared in a file named MongoDBTodoServiceTest.java
        [INFO] 1 error
        [INFO] -------------------------------------------------------------
        [INFO] ------------------------------------------------------------------------
        [INFO] BUILD FAILURE
        [INFO] ------------------------------------------------------------------------
        [INFO] Total time: 3.372 s
        [INFO] Finished at: 2017-05-23T11:48:04+02:00
        [INFO] Final Memory: 20M/219M

        • Petri May 23, 2017 @ 13:19

          Oops :( Thank you for reporting this problem. It is fixed now.

          • kiran May 23, 2017 @ 13:49

            Hi Petri, what did you change ? where can i get that fixed file ?

          • kiran May 23, 2017 @ 14:18

            I have managed to fix the issue

          • Petri May 30, 2017 @ 22:31

            Hi, I probably should I have mentioned that I fixed the problem and committed the fix to Github. In any case, it's good hear that you were able to solve your problem.

  • Bogu Oct 25, 2016 @ 14:41

    Hi Petri,
    I follow your guide and i had created similar proyect in NetBEans. But i have some problem with run of MongoDb, when i run the application my program is throwing an exception:

    [localhost:27017] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27017
    com.mongodb.MongoSocketOpenException: Exception opening socket
    /....

    After this exception Tomcat is starting but because of that problem i can't store any date in MongoDb, do u have some ideas how to resolve this issue??

    Best regards

    • Petri Oct 25, 2016 @ 15:37

      It seems that the application cannot open a database connection for some reason. Are using a local or a remote MongoDB instance? In any case, I would check that the connection string is correct and that MongoDB is listening the "correct" port (this depends from your configuration).

      • Bogu Oct 25, 2016 @ 16:25

        I reinstalled my MongoDb to newest version and after starting mongoDB server i run my application and works perfectly. Magic lol :D Big thanks for help!!

        • Petri Nov 2, 2016 @ 12:20

          You are welcome! I am happy to hear that you were able to solve your problem.

  • Dani Feb 7, 2017 @ 17:04

    Hi
    How can I add my custom methods and link them to a custom rest call?

  • Anonymous Mar 22, 2017 @ 20:43

    It's very helpful tutorial. Thanks Alot.

  • ben Mar 23, 2017 @ 8:35

    I get:
    [ERROR] No plugin found for prefix 'spring' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (/home/ben/.m2/repository), spring-releases (https://repo.spring.io/libs-release), central (http://repo.maven.apache.org/maven2)] -> [Help 1]
    org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException: No plugin found for prefix 'spring' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (/home/ben/.m2/repository), spring-releases (https://repo.spring.io/libs-release), central (http://repo.maven.apache.org/maven2)]
    at org.apache.maven.plugin.prefix.internal.DefaultPluginPrefixResolver.resolve(DefaultPluginPrefixResolver.java:94)

    Drives me nuts didnt find any help on google

    • Petri Mar 27, 2017 @ 21:10

      Hi,

      I haven't seen this error myself, but if you are trying to run the example application of this blog post and you get this error, you might want to update the Spring Boot Maven plugin. The example uses rather old Spring Boot version and the configuration might have changed in newer versions (I cannot remember if this is the case though).

  • nuugut Mar 31, 2017 @ 16:43

    Hi Petri,
    How to config mongoDB connection?
    In normal JAVA I have to connect to mongodb first before do anything in database, like this.

    MongoClient mongoClient = new MongoClient("localhost", 27017);

    in the tutorial there's not any connection in code.

    Thanks

    • Petri Apr 3, 2017 @ 22:29

      Hi,

      Take a look at the Spring Boot's Reference Documentation. The section 30.2 MongoDB answers to your question.

  • Devin Jul 19, 2017 @ 8:19

    What is the purpose of the TodoDTO class? Why is it important to have this?

    • Petri Jul 19, 2017 @ 11:24

      The TodoDTO class is a data transfer object that simply hides the data model (basically entities) of the example application from the outside world. This allows you to change the data model without breaking the clients that use your API (assuming that you can still use the same DTOs).

      By the way, it's also important to realize that you might not need this if you are writing prototypes or internal APIs because you can update the clients at the same time you update your API. However, if you are writing a public API, you have to be more cautious because it's not a good idea to break your API every time you make changes to your data model.

  • Kunal Oct 2, 2017 @ 21:22

    have you thought about one to many embedded documents collection in Mongodb? instead of just saving new document every time? This way you can also take care of multiple users.

    your new mongodb document -
    {
    id: xxjjjx,
    userName: kunal;
    todoList:[
    {
    id:xx
    todo: "whatever"
    },
    {
    id:xx2
    todo: "whatever"
    }
    ]
    }

  • Ami Aug 24, 2019 @ 8:42

    Hi Petrik,
    We have a requirement to design our application business logic in a DB neutral way. Which implies that our service layer will data model. We will get data from our Rest API base on that we will fetch our domain model from DB. So there will be a conversion layer which will translate stored data into a service layer data model. We want to design our service layer domain model, not in the way we are storing it in DB so that we can switch our DB with minimal or zero impact to our business logic. Is this a good way to think in this direction?
    Is there any framework already exists?
    Do you have any recommendation/best practices on it?

  • Arvind Jan 4, 2020 @ 8:47

    Hi,
    Can we use spring 3.2 with spring data mongodb version 2.2.3.Release.

Leave a Reply