/spring-mongodb-example

This is the Spring guide "Accessing MongoDB Data with REST":

Primary LanguageShell

tags projects
spring-data
mongodb
rest
hateoas
spring-data-rest

This guide walks you through the process of creating an application that accesses document-based data through a hypermedia-based RESTful front end.

What you’ll build

You’ll build a Spring application that let’s you create and retrieve Person objects stored in a MongoDB NoSQL database using Spring Data REST. Spring Data REST takes the features of Spring HATEOAS and Spring Data MongoDB and combines them together automatically.

Note
Spring Data REST also supports Spring Data JPA, Spring Data Gemfire and Spring Data Neo4j as backend data stores, but those are not part of this guide.

What you’ll need

Install and launch MongoDB

For this guide to work, you must stand up a local MongoDB server.

On a Mac OS X machine with homebrew, just do this:

brew install mongodb

More installation options are found at http://docs.mongodb.org/manual/installation/.

After installing it, you need to launch the mongo daemon.

$ mongod
all output going to: /usr/local/var/log/mongodb/mongo.log

The MongoDB client that is also installed can be started from another terminal window by typing mongo.

Create a domain object

Create a new domain object to present a person.

src/main/java/hello/Person.java

link:complete/src/main/java/hello/Person.java[role=include]

The Person has a first name and a last name. There is also an id object that is configured to be automatically generated so you don’t have to deal with that.

Create a Person repository

Next you need to create a simple repository.

src/main/java/hello/PersonRepository.java

link:complete/src/main/java/hello/PersonRepository.java[role=include]

This repository is an interface and will allow you to perform various operations involving Person objects. It gets these operations by extending MongoRepository, which in turn extends the PagingAndSortingRepositry interface defined in Spring Data Commons.

At runtime, Spring Data REST will create an implementation of this interface automatically. Then it will use the @RepositoryRestResource annotation to direct Spring MVC to create RESTful endpoints at /people.

Note
@RepositoryRestResource is not required for a repository to be exported. It is only used to change the export details, such as using /people instead of the default value of /persons.

Here you have also defined a custom query to retrieve a list of Person objects based on the lastName. You’ll see how to invoke it further down in this guide.

Note
Spring Boot by default attempts to connect to a locally hosted instance of MongoDB. Read the reference docs for details on pointing your app to an instance of MongoDB hosted elsewhere.

Make the application executable

Although it is possible to package this service as a traditional WAR file for deployment to an external application server, the simpler approach demonstrated below creates a standalone application. You package everything in a single, executable JAR file, driven by a good old Java main() method. Along the way, you use Spring’s support for embedding the Tomcat servlet container as the HTTP runtime, instead of deploying to an external instance.

src/main/java/hello/Application.java

link:complete/src/main/java/hello/Application.java[role=include]

@SpringBootApplication is a convenience annotation that adds all of the following:

  • @Configuration tags the class as a source of bean definitions for the application context.

  • @EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.

  • Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.

  • @ComponentScan tells Spring to look for other components, configurations, and services in the the hello package, allowing it to find the HelloController.

The main() method uses Spring Boot’s SpringApplication.run() method to launch an application. Did you notice that there wasn’t a single line of XML? No web.xml file either. This web application is 100% pure Java and you didn’t have to deal with configuring any plumbing or infrastructure.

Logging output is displayed. The service should be up and running within a few seconds.

Test the application

Now that the application is running, you can test it. You can use any REST client you wish. The following examples use the *nix tool curl.

First you want to see the top level service.

$ curl http://localhost:8080
{
  "_links" : {
    "people" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    }
  }
}

Here you get a first glimpse of what this server has to offer. There is a people link located at http://localhost:8080/people. It has some options such as ?page, ?size, and ?sort.

Note
Spring Data REST uses the HAL format for JSON output. It is flexible and offers a convenient way to supply links adjacent to the data that is served.
$ curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

There are currently no elements and hence no pages. Time to create a new Person!

Note
If you run this guide multiple times, there may be left over data. Refer to the MongoDB shell quick reference to find commands to find and drop your database if you need a fresh start.
$ curl -i -X POST -H "Content-Type:application/json" -d '{  "firstName" : "Frodo",  "lastName" : "Baggins" }' http://localhost:8080/people
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Location: http://localhost:8080/people/53149b8e3004990b1af9f229
Content-Length: 0
Date: Mon, 03 Mar 2014 15:08:46 GMT
  • -i ensures you can see the response message including the headers. The URI of the newly created Person is shown

  • -X POST signals this a POST used to create a new entry

  • -H "Content-Type:application/json" sets the content type so the application knows the payload contains a JSON object

  • -d '{ "firstName" : "Frodo", "lastName" : "Baggins" }' is the data being sent

Note
Notice how the previous POST operation includes a Location header. This contains the URI of the newly created resource. Spring Data REST also has two methods on RepositoryRestConfiguration.setReturnBodyOnCreate(…) and setReturnBodyOnCreate(…) which you can use to configure the framework to immediately return the representation of the resource just created.

From this you can query for all people:

$ curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "_embedded" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/53149b8e3004990b1af9f229"
        }
      }
    } ]
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}

The persons object contains a list with Frodo. Notice how it includes a self link. Spring Data REST also uses Evo Inflector to pluralize the name of the entity for groupings.

You can query directly for the individual record:

$ curl http://localhost:8080/people/53149b8e3004990b1af9f229
{
  "firstName" : "Frodo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/53149b8e3004990b1af9f229"
    }
  }
}
Note
This might appear to be purely web based, but behind the scenes, it is talking to the MongoDB database you started.

In this guide, there is only one domain object. With a more complex system where domain objects are related to each other, Spring Data REST will render additional links to help navigate to connected records.

Find all the custom queries:

$ curl http://localhost:8080/people/search
{
  "_links" : {
    "findByLastName" : {
      "href" : "http://localhost:8080/people/search/findByLastName{?name}",
      "templated" : true
    }
  }
}

You can see the URL for the query including the HTTP query parameter name. If you’ll notice, this matches the @Param("name") annotation embedded in the interface.

To use the findByLastName query, do this:

$ curl http://localhost:8080/people/search/findByLastName?name=Baggins
{
  "_embedded" : {
    "persons" : [ {
      "firstName" : "Frodo",
      "lastName" : "Baggins",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/people/53149b8e3004990b1af9f229"
        }
      }
    } ]
  }
}

Because you defined it to return List<Person in the code, it will return all of the results. If you had defined it only return Person, it will pick one of the Person objects to return. Since this can be unpredictable, you probably don’t want to do that for queries that can return multiple entries.

You can also issue PUT, PATCH, and DELETE REST calls to either replace, update, or delete existing records.

$ curl -X PUT -H "Content-Type:application/json" -d '{ "firstName": "Bilbo", "lastName": "Baggins" }' http://localhost:8080/people/53149b8e3004990b1af9f229
$ curl http://localhost:8080/people/53149b8e3004990b1af9f229
{
  "firstName" : "Bilbo",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/53149b8e3004990b1af9f229"
    }
  }
}
$ curl -X PATCH -H "Content-Type:application/json" -d '{ "firstName": "Bilbo Jr." }' http://localhost:8080/people/53149b8e3004990b1af9f229
$ curl http://localhost:8080/people/53149b8e3004990b1af9f229
{
  "firstName" : "Bilbo Jr.",
  "lastName" : "Baggins",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people/53149b8e3004990b1af9f229"
    }
  }
}
Note
PUT replaces an entire record. Fields not supplied will be replaced with null. PATCH can be used to update a subset of items.

You can delete records:

$ curl -X DELETE http://localhost:8080/people/53149b8e3004990b1af9f229
$ curl http://localhost:8080/people
{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/people{?page,size,sort}",
      "templated" : true
    },
    "search" : {
      "href" : "http://localhost:8080/people/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}

A very convenient aspect of this hypermedia-driven interface is how you can discover all the RESTful endpoints using curl (or whatever REST client you are using). There is no need to exchange a formal contract or interface document with your customers.

Summary

Congratulations! You’ve just developed an application with a hypermedia-based RESTful front end and a MongoDB-based back end.