DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Data Engineering
  3. Databases
  4. Introduction to HATEOAS With Spring Boot Data Rest

Introduction to HATEOAS With Spring Boot Data Rest

Learn how to implement Spring Data Rest for APIs to analyze domain models and expose Hypermedia Driven REST endpoints automatically.

Mohit Sinha user avatar by
Mohit Sinha
·
Nov. 01, 17 · Tutorial
Like (6)
Save
Tweet
Share
15.80K Views

Join the DZone community and get the full member experience.

Join For Free

HATEOAS (Hypermedia as the Engine of Application State) specifies that REST APIs should provide enough information to the client to interact with the server. This is different from SOA (Service-Oriented Architecture) where a client and a server interact through a fixed contract. We'll look more into HATEOAS in a while.

Spring Data Rest is built on top of Spring Data, Spring Web MVC & Spring Hateos. It analyzes all the domain models and exposes Hypermedia Driven REST endpoints for them automatically. In the meanwhile, all the features of Spring Data Repositories like sorting, pagination, etc. are available in these endpoints.

We'll see with the help of a very simple example how to implement this.

Dependencies

We'll use Gradle to build our project.

dependencies {
    compile("org.springframework.boot:spring-boot-starter-data-rest")
    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
    compile("com.h2database:h2")
    compileOnly('org.projectlombok:lombok')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}


We'll use H2 to run our project. The same concept can be applied to different databases like MongoDB, MySQL etc. The full list of supported databases is given here.

Spring Data Rest

In this example, we'll use JPA to create cities and countries.

Let's have a look at our Country class.

@Data
@Entity
@RestResource
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Country {
    @GeneratedValue
    @Id Long id;
    String name;
}


Let's have a look at our City class.

@Data
@Entity
@NoArgsConstructor
@RestResource
@FieldDefaults(level = AccessLevel.PRIVATE)
public class City {
    @GeneratedValue
    @Id Long id;
    String name;
    @ManyToOne Country country;
}


As we are using JPA in our project, we are creating an association between a City and a Country. Many Cities can be associated with a Country.

Let's create the repositories for them.

public interface CountryRepository extends JpaRepository<Country, Long> {}


This will create a repository for Country and also expose the REST endpoints (GET, POST, PUT, DELETE, PATCH) for the same. As JPARepository extends PagingAndSortingRepository, paging & sorting functionality will be automatically added for the GET endpoint. By default, the path is derived from the uncapitalized, pluralized, simple class name of the domain class being managed. In our case, the path will be countries.

@RepositoryRestResource(path = "metropolises")
public interface CityRepository extends JpaRepository<City, Long> {}


We have customized the path to metropolises.

HATEOAS

Let's check the APIs after we run our project.

curl 'http://localhost:8080'
{
   "_links": {
       "countries": {
           "href": "http://localhost:8080/countries{?page,size,sort}",
           "templated": true
       },
       "cities": {
           "href": "http://localhost:8080/metropolises{?page,size,sort}",
           "templated": true
       },
       "profile": {
           "href": "http://localhost:8080/profile"
       }
   }
}


We get some information about the available APIs. We can further explore about the metadata by hitting the profile API. You can read more about the metadata here.

Let's add a few Countries.

curl 'http://localhost:8080/countries' -X POST -d '{"name":"Japan"}' -H 'Content-Type: application/json'
curl 'http://localhost:8080/countries' -X POST -d '{"name":"India"}' -H 'Content-Type: application/json'
curl 'http://localhost:8080/countries' -X POST -d '{"name":"Germany"}' -H 'Content-Type: application/json'
curl 'http://localhost:8080/countries' -X POST -d '{"name":"Canada"}' -H 'Content-Type: application/json'
curl 'http://localhost:8080/countries' -X POST -d '{"name":"Australia"}' -H 'Content-Type: application/json'


Let's fetch a paginated result of Countries with the results sorted by Country name, the page size 2 and the 1st page.

curl 'http://localhost:8080/countries/?sort=name,asc&page=1&size=2'
{
    "_embedded": {
        "countries": [
            {
                "name": "Germany",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/countries/3"
                    },
                    "country": {
                        "href": "http://localhost:8080/countries/3"
                    }
                }
            },
            {
                "name": "India",
                "_links": {
                    "self": {
                        "href": "http://localhost:8080/countries/2"
                    },
                    "country": {
                        "href": "http://localhost:8080/countries/2"
                    }
                }
            }
        ]
    },
    "_links": {
        "first": {
            "href": "http://localhost:8080/countries?page=0&size=2&sort=name,asc"
        },
        "prev": {
            "href": "http://localhost:8080/countries?page=0&size=2&sort=name,asc"
        },
        "self": {
            "href": "http://localhost:8080/countries"
        },
        "next": {
            "href": "http://localhost:8080/countries?page=2&size=2&sort=name,asc"
        },
        "last": {
            "href": "http://localhost:8080/countries?page=2&size=2&sort=name,asc"
        },
        "profile": {
            "href": "http://localhost:8080/profile/countries"
        }
    },
    "page": {
        "size": 2,
        "totalElements": 5,
        "totalPages": 3,
        "number": 1
    }
}


Apart from the expected countries, we also get the links to different pages and further information that might help in handling pagination better.

The links to the first, previous, self, next and last pages can directly be used.

Let's add a City and associate it with a Country.

curl 'http://localhost:8080/metropolises' -X POST -d '{"name":"Osaka", "country":"http://localhost:8080/countries/1"}' -H 'Content-Type: application/json'

We have to pass the url of the country and this will be mapped to Japan. We saved Japan first, hence its id is 1.

Let's see what we get when we fetch that City.

curl 'http://localhost:8080/metropolises/1'
{
    "name": "Osaka",
    "_links": {
        "self": {
            "href": "http://localhost:8080/metropolises/1"
        },
        "city": {
            "href": "http://localhost:8080/metropolises/1"
        },
        "country": {
            "href": "http://localhost:8080/metropolises/1/country"
        }
    }
}


We are getting a link to the Country associated with it. Let's see what we get in response for it.

{
    "name": "Japan",
    "_links": {
        "self": {
            "href": "http://localhost:8080/countries/1"
        },
        "country": {
            "href": "http://localhost:8080/countries/1"
        }
    }
}


Conclusion

I have tried explaining, with a simple example, how to create REST applications using Spring Data Rest. You can read more about setting up policies and integrating with Spring Security here.

You can find the complete example on GitHub.

Spring Framework Data (computing) Spring Boot Spring Data Database Spring Security REST Web Protocols application

Published at DZone with permission of Mohit Sinha, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Use Terraform to Provision an AWS EC2 Instance
  • Understanding gRPC Concepts, Use Cases, and Best Practices
  • Iptables Basic Commands for Novice
  • What Should You Know About Graph Database’s Scalability?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: