spring-projects / spring-data-rest

Simplifies building hypermedia-driven REST web services on top of Spring Data repositories
https://spring.io/projects/spring-data-rest
Apache License 2.0
915 stars 561 forks source link

Allow return of intermediate resources when traversing releations [DATAREST-412] #789

Open spring-projects-issues opened 9 years ago

spring-projects-issues commented 9 years ago

daniel carter opened DATAREST-412 and commented

This Issue relates to Traverson, which is part of spring-hateoas, as a client to spring-data-rest. Hateoas doesn't have JIRA project, so hopefully this is the correct place for tickets.

When using Traverson, i can only retrieve the resource at the end of the traversal. It is often useful to retrieve the intermediate objects.

For instance i have CREDENTIALS, which are linked to an IDENTITY, which has a (main) CONTACT which has some ROLEs.

For a credential, i want to retrieve the identity and its contacts roles.

This gives me the contact roles, but there is no way to get at the identity.

Traverson t = new Traverson(new URI("http://127.0.0.1:8090/"), MediaTypes.HAL_JSON);
t.setRestOperations(template);
Map<String, Object> params = new HashMap<>();
params.put("name", "V6UqkSG8");
params.put("type", "myType");
String contactUuid = t.follow("credentials", "search", "byNameAndType", "$_embedded.credentials[0]._links.identity.href", "mainContact", "roles")
        .withTemplateParameters(params).<String> toObject(String.class);

I can retrieve both this way, but's it's ugly.

        Traverson t = new Traverson(new URI("http://127.0.0.1:8090/"), MediaTypes.HAL_JSON);
        t.setRestOperations(template);
        Map<String, Object> params = new HashMap<>();
        params.put("name", "V6UqkSG8");
        params.put("type", "myType");
        String identity = t.follow("credentials", "search", "byNameAndType", "$_embedded.credentials[0]._links.identity.href")
                .withTemplateParameters(params).toObject(String.class);

        LinkDiscoverer linkDiscoverer = new HalLinkDiscoverer();
        Link contactLink = linkDiscoverer.findLinkWithRel("mainContact", identity);

        t = new Traverson(new URI(contactLink.getHref()), MediaTypes.HAL_JSON);
        t.setRestOperations(template);
        String contactRoles = t.follow("roles").<String> toObject(String.class);

A few options 1) Traverson could be stateful, retrieving an object and remembering it to allow a subsequent follow to resume from that resource

String identity = t.follow("credentials", "search", "byNameAndType", "$_embedded.credentials[0]._links.identity.href").toObject(String.class);
String contactRoles = t.follow("mainContact", "roles").toObject(String.class);

2) Traverson could store everything for later retrieval

String contactRoles = t.follow("credentials", "search", "byNameAndType", "$_embedded.credentials[0]._links.identity.href", "mainContact", "roles").toObject(String.class);
String contact = t.retrieveFromTraverse("mainContact").toObject(String.class);
String identity = t.retreiveFromTraverse("$_embedded.credentials[0]._links.identity.href").toObject(String.class);

3) Traverson could optionally return some sort of intermediate object to hold state

TraversonState identityTS = t.follow("credentials", "search", "byNameAndType", "$_embedded.credentials[0]._links.identity.href").toState();
String identity = identityTS.toObject(String.class);
String contactRoles = identityTS.follow("mainContact", "roles");

All much clearner looking than

        String identity = t.follow("credentials", "search", "byNameAndType", "$_embedded.credentials[0]._links.identity.href")
                .withTemplateParameters(params).toObject(String.class);

        LinkDiscoverer linkDiscoverer = new HalLinkDiscoverer();
        Link contactLink = linkDiscoverer.findLinkWithRel("mainContact", identity);

        t = new Traverson(new URI(contactLink.getHref()), MediaTypes.HAL_JSON);
        t.setRestOperations(template);
        String contactRoles = t.follow("roles").<String> toObject(String.class);

PS. It would be nice if spring-data-rest would return a single object from a query method whoose signature returns a single entity to avoid all the "$_embedded.credentials[0]._links.identity.href" stuff.


Affects: 2.2.1 (Evans SR1)

spring-projects-issues commented 9 years ago

daniel carter commented

Ok, just found a reference to the hateoas bug tracker in the comments of another ticket. Might help things if there was a link on the project page. http://projects.spring.io/spring-hateoas/

Posted https://github.com/spring-projects/spring-hateoas/issues/266