This guide walks you through the process of creating an application that accesses data stored in Apache Geode through a hypermedia-based REST-ful frontend.
You’ll build a Spring Web application that let’s you create and retrieve Person
objects stored in the
Apache Geode In-Memory Data Grid (IMDG) using Spring Data REST.
Spring Data REST takes the features of Spring HATEOAS
and Spring Data for Apache Geode and combines them together
automatically.
Note
|
Spring Data REST also supports Spring Data JPA, Spring Data MongoDB and Spring Data Neo4j as backend data stores, but those are not part of this guide. |
Tip
|
For more general knowledge of Apache Geode concepts and accessing data from Apache Geode, read through the guide, Accessing Data with Apache Geode. |
For all Spring applications, you should start with the Spring Initializr. Spring Initializr offers a fast way to pull in all the dependencies you need for an application and does a lot of the set up for you. This example needs "Spring for Apache Geode" dependency.
The following listing shows an example pom.xml
file when using Maven:
link:complete/pom.xml[role=include]
The following listing shows an example build.gradle
file when using Gradle:
link:complete/build.gradle[role=include]
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 and last name. Apache Geode domain objects need an id, so an AtomicLong
is being used
to increment with each Person
object creation.
Next, you need to create a simple Repository to persist/access Person
objects stored in Apache Geode.
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 data access operations (e.g. basic CRUD
and simple queries) involving Person
objects. It gets these operations by extending CrudRepository
.
At runtime, Spring Data for Apache Geode will create an implementation of this interface automatically.
Then, Spring Data REST will use the
@RepositoryRestResource
annotation to direct Spring MVC to create REST-ful 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 lastName
. You’ll see how to
invoke it further down in this guide.
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 servlet container.
src/main/java/hello/Application.java
link:complete/src/main/java/hello/Application.java[role=include]
The @EnableGemfireRepositories
annotation activates Spring Data for Apache Geode Repositories.
Spring Data for Apache Geode will create a concrete implementation of the PersonRepository
interface
and configure it to talk to an embedded instance of Apache Geode.
Logging output is displayed. The service should be up and running within a few seconds.
Now that the application is running, you can test it. You can use any REST client you wish. The following examples uses
the *nix tool curl
.
First you want to see the top level service.
$ curl http://localhost:8080
{
"_links" : {
"people" : {
"href" : "http://localhost:8080/people"
}
}
}
Here you get your first glimpse of what this server has to offer. There is a people link located at http://localhost:8080/people. Spring Data for Apache Geode doesn’t support pagination like the other Spring Data REST guides so there are no extra navigational links.
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" : {
"search" : {
"href" : "http://localhost:8080/people/search"
}
}
}
Time to create a new Person
!
$ 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/1
Content-Length: 0
Date: Wed, 05 Mar 2014 20:16:11 GMT
-
-i
ensures you can see the response message including the headers. The URI of the newly createdPerson
is shown -
-X POST
issues aPOST
HTTP request 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" : {
"search" : {
"href" : "http://localhost:8080/people/search"
}
},
"_embedded" : {
"persons" : [ {
"firstName" : "Frodo",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
} ]
}
}
The people collection resource 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/1
{
"firstName" : "Frodo",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
}
Note
|
This might appear to be purely web based, but behind the scenes, it is talking to an embedded Apache Geode database. |
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/1"
}
}
} ]
}
}
Because you defined it to return List<Person>
in the code, it will return all of the results. If you had defined it
to only return Person
, it would 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/1
$ curl http://localhost:8080/people/1
{
"firstName" : "Bilbo",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
}
$ curl -X PATCH -H "Content-Type:application/json" -d '{ "firstName": "Bilbo Jr." }' http://localhost:8080/people/1
$ curl http://localhost:8080/people/1
{
"firstName" : "Bilbo Jr.",
"lastName" : "Baggins",
"_links" : {
"self" : {
"href" : "http://localhost:8080/people/1"
}
}
}
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/1
$ curl http://localhost:8080/people
{
"_links" : {
"search" : {
"href" : "http://localhost:8080/people/search"
}
}
}
A very convenient aspect of this hypermedia-driven interface is how you can discover
all the REST-ful 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.
Congratulations! You’ve just developed an application with a hypermedia-based RESTful frontend and a Apache Geode-based backend.
The following guides may also be helpful: