How to put and post links with Spring HATEOAS

Andrew Hill picture Andrew Hill · Oct 10, 2014 · Viewed 7.8k times · Source

I'm trying to understand how to create and modify links in Spring HATEOAS.

For example, say I have two collections, one at api/users and another at api/event. I would like to associate a user api/user/56 with an event api/event/21. For arguments sake this is a many-to-many - a user may attend many events, an event may have many users.

As I understand it, the restful way of doing this is to use the URIs as primary keys, so I might post the following to api/user/56/events;

{
    attends: "http://localhost:9090/api/event/21"
}

The endpoint then needs to be able to parse that URL and extract the ID (in this case 21) and the controller (EventController.class) so that I can persist this.

Question 1: Is this the correct way of dealing with relationships in Spring Hateoas in terms of the REST API?

Question 2: How can I resolve this url in a controller to a usable handle on the data (for example a reference to the appropriate controller/method, a primary key, etc)

Research

RestTemplate can be used to request the data from the controller inside the request mapped method, like so;

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<EventResource> response = restTemplate.getForEntity(attendsUrl, EventResource.class);
EventResource eventResource = response.getBody();

However I don't believe that eventResource should return an Id field as part of the data - it's not very restful and this would be exposed on the API. One approach is to have a parameter "includePK=true" but again this doesn't feel right - it's just hiding the problem. Moreover the idea of the server making requests to it's own API in this manner seems circuitous.

Update

There is an open question for this here https://github.com/spring-projects/spring-hateoas/issues/292. Based loosely on some of the comments (by user kevinconaway) from that issue I have made a quick util class that offers an easy solution here: SpringHateoasUtils. The solution boils down to;

String mapping = DISCOVERER.getMapping(targetClass, targetMethod);
UriTemplate template = new UriTemplate(mapping);
//values is key/value map of parameters that the referenced method accepts
Map<String, String> values = uriTemplate.match(uri);

SpringHateoasUtils makes this slightly nicer but it still feels like it should be a feature. I'll seek to get something in the spring code for this - when it's clear what is happening with this I'll answer this question.

Answer

Robert picture Robert · Jan 5, 2017

Look at the answer here:

POSTing a @OneToMany sub-resource association in Spring Data REST

Question 1) Yes this is how you post links/relations. With URIs.

Question 2) The URI of the resource actually IS its ID from the client's perspective. The server internally automatically resolves this URI into the actual model instance with

org.springframework.data.rest.core.UriToEntityConverter.convert(...)