How to put and post links with Spring HATEOAS
Asked Answered
R

1

11

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.

Repossess answered 9/10, 2014 at 22:29 Comment(2)
You would post http://localhost:9090/api/event/21 only. Spring HATEOAS doesn't help you to dereference a URL. It's only meant for responses, not requests. You might take a look at Spring Data RESTSwinford
Having worked with Spring HATEOAS for several months it definitely does not appear to support REST properly, so I have had to implement similar workarounds to what you are describing.Reareace
B
4

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(...)

Bautista answered 5/1, 2017 at 8:17 Comment(2)
This is a question about Spring Hateoas - although Spring Data Rest allows for limited use of links, Spring Data Rest falls short of providing a way of implementing ones own link handling functionality.Repossess
Hello Andrew! Did you have look at the link I posted? It also took me a while to understand the subtle differences. But meanwhile I found out how to archive what you are trying to do: Spring Data HATEOAS allows to "create" links between to entities by posting a text/uri-list e.g. like this: curl -X PUT -H "ContentType: text/uri-list" http://localhost:8080/api/myEntitty/1 with the link uri as payload http://localhost:8080/api/myLinkedChildEntity/4711 If you need more low-level access the you can always implement your own @RestController in spring restBautista

© 2022 - 2024 — McMap. All rights reserved.