spring-hateoas icon indicating copy to clipboard operation
spring-hateoas copied to clipboard

Add Traverson support to the usual HTTP method verbs (POST, PUT, DELETE and PATCH)

Open palpa opened this issue 10 years ago • 18 comments

Similar to what the actual javascript client support: https://github.com/basti1302/traverson#post-put-delete-and-patch

palpa avatar Aug 11 '14 14:08 palpa

I would also be very interested in this enhancement. Is it perhaps planned for a future release, @olivergierke ? Anywhere we can help out?

andreasevers avatar Nov 13 '14 11:11 andreasevers

+1.. Anyone?

vicmosin avatar Apr 28 '15 07:04 vicmosin

It looks quite simple, and would certainly be nice to have, for example the following could be added to TraversalBuilder:

public <T> ResponseEntity<T> postForEntity(Object payload, Class<T> type) {
    Assert.notNull(type, "Target type must not be null!");
    return operations.exchange(traverseToFinalUrl(true), POST, 
            prepareRequest(headers, payload), type);
}

Where an additional prepareRequest overload is added to allow request with body to be created.

nealeu avatar Jul 30 '15 14:07 nealeu

+1

RaySinnema avatar Oct 18 '15 14:10 RaySinnema

+1

johndeverall avatar Dec 02 '15 21:12 johndeverall

+1

ArturGajowy avatar Feb 10 '16 12:02 ArturGajowy

+1

otrosien avatar Feb 20 '16 14:02 otrosien

+1

egorlitvinenko avatar Mar 11 '17 15:03 egorlitvinenko

I'd love to learn more about the actual use-cases to include non-safe and non-idempotent HTTP methods in the traversal.

The reason I am curious about this that I so far considered a traversal something that's a discovery of resources to eventually end up at one that a more advanced business operation is invoked on. That sort of implies repeatability of the traversal which breaks apart if the traversal contains non-safe or non-idempotent HTTP requests.

For example, see how this traversal basically looks up a resource and the client the uses the eventually discovered link to expand that and let the actual client do whatever it wants with it. That way the discovery is separated from the final invocation and can be refreshed automatically, e.g. in case the resource becomes outdated and needs to be rediscovered, something the Spring Cloud integration does for you automatically.

odrotbohm avatar Mar 12 '17 13:03 odrotbohm

Oh, and in case you missed it, GitHub has a voting feature that can be used on the original comment to indicate support. No need to add more "+1" comments :).

odrotbohm avatar Mar 12 '17 13:03 odrotbohm

  1. The business operation could consists of multiple steps. E.g. you start the process with POST, but then you need to perform additional operations on the created resource. An example would be ordering a book from a bookstore, where the initial POST puts a book in your cart, but there are further steps in the process to actually buy the book, like adding a delivery address and payment method. It would be great if we could continue those steps with the same ease as the initial navigation.
  2. The business operation could also result in the creation of multiple new resources. The root of that resource tree is returned as the result of the POST, and you may want to navigate from there to inspect or operate on any of the sub-resources. This is quite prevalent in testing scenarios (builder pattern), but there are other use cases as well. One example would be inspecting the line items of an order.

RaySinnema avatar Mar 12 '17 14:03 RaySinnema

And that's quite analogous to reactor flows. I wonder if this is something better served when we add reactor support.

gregturn avatar Mar 12 '17 14:03 gregturn

Hm, I see. Traverson is currently not built to be a generic HTTP client or the central API to build an interaction with a REST API around, but one to discover resources by following links (as the both the JavaDoc and the API clearly express). It currently also lacks the ability of dynamically inspecting responses and reacting on the presence or non-presence of links, which also should make this very obvious. This in turn means that the rather technical request to add support for other HTTP methods sort of contradicts the current design constraints and is basically asking the wrong question :).

Also, I've never understood "following a link" — which is the only thing exposed in the API currently — to be anything else than a GET, mostly because also in HTML there's a clear distinction between following (clicking) links on an anchor and issuing commands through forms. I am not sure that blending these two things is a good idea. I actually like the fact that Traverson does one thing and serves that one thing well.

The whole point about Traverson is that it doesn't need any more knowledge about the server than link relations, URI templates and how to expand them as well as hypermedia types. All the things you describe already use API specifics (i.e. what exactly to post to a URI) and embrace a lot more dynamics. Think of it as the guide that finds a product at Amazon, but then let's you figure out what to do with it.

If you want much more control over all this, I wonder what the benefit of a wrapping Traverson actually is compared to a RestTemplate that you use alongside a LinkDiscoverer to transparently find links. Actually, I'd rather think about a more high level API (maybe even built on top of Traverson) to implement such interactions with an API instead of starting to bolt things on Traverson that end up in a rabbit hole and something that had a well defined purpose and scope to then dilute.

odrotbohm avatar Mar 12 '17 14:03 odrotbohm

I thought this was supposed to be a port of the original Traverson, which provides such features. If they're not going to be added, then the number of use cases that can be addressed with this project are so small that I don't see the point, really.

RaySinnema avatar Mar 12 '17 15:03 RaySinnema

In my case I has an integration system, which receives message from outside and store it in another system with REST API. RestTemplate is wrapped for POST/PUT/GET and use Traverson for search methods. So now for each domain object we add Service inherited from wrapper and give miracle SPI for Server's Resources. In wrapper class I see three different code styles to communicate with server, for example methods: postForLocation, getForEntity; custom method exchange (for PUT) and Traverson for search. With restTemplate there is boilerplate code like headers creation, parameters, ResponseEntity result processing, etc.

The class is mixed, if it possible I prefer one code style. As for me Traverson is simpler because we can use chained methods to build it and run requests lazely, as it performs only in toObject and toEntity methods.

Actually, I'd rather think about a more high level API (maybe even built on top of Traverson) to implement such interactions with an API instead of starting to bolt things on Traverson that end up in a rabbit hole and something that had a well defined purpose and scope to then dilute.

Yes, I agree it can be better. Ideally for us and I think it will be usefull for other users who use Spring Data REST, is to have client in the same way as server out of the Spring box. I know there are some community implementations, but it will be more serious to have one from Spring. :)

I mean something like:

@NoRepositoryBean
api.DomainObjectService

@RepositoryRestResource
spi.server.DomainObjectService extends api.DomainObjectService

@RepositoryRestResourceClient
spi.server.DomainObjectService extends api.DomainObjectService

Then resolve HTTP methods by default with names. Or with overrides and Annotations: @Put, @Get, ... I see that it's can be not the best solution, for example, because of @Query, which we don't need on client side. But it's save time and maybe to think in this direction.

egorlitvinenko avatar Mar 12 '17 18:03 egorlitvinenko

Interesting conversation. In my case I wanted the other verbs so that I could perform a number of GET requests / traversal steps but then make a (potentially) non idempotent operation at the end of the chain.

@olivergierke you'll see I've hacked (admittedly not very well) your code here to do what I wanted in terms of PUT, POST and DELETE using Traverson.

The actual modified Traverson package is here.

You can see the real life use case in README.md or you can just run the console app.

Stuff I care about:

  1. Following the links using GET and then performing a possibly non idempotent operation in the final hop.

  2. Some kind of caching mechanism for content that hasn't changed. This could be using If-Modified-Since or perhaps caching available links for the life of a user session.

  3. Some kind of authentication / session management. So, somebody logs in, they get a bunch of links which may not be the same as another users bunch of links. When they log out, cache is cleared.

  4. A single library I don't have to think about much.

Maybe I'm asking too much or my use case is too specific :)

johndeverall avatar Mar 13 '17 12:03 johndeverall

Idempotence as a design goal in this case seems a bit unexpected. While graph traversal IS based on a set of non-modifying operations, the idea of some sequences of steps needing to always be repeatable seems unlikely, especially since for practical purposes most systems expose multiple ways to modify the backing data independently and thus the traversal would change as well.

I see there are cases for this "locked down" approach, but maybe both it and a more robust set of methods can be supported by configuring which features one wishes to expose or consume. Since the server can choose the former, it makes sense of clients (like Traverson) to allow choice in the latter - being able to configure a non-modifying client.

I think the main point is: RestTemplate is still a bit klunky, and for Hateoas APIs Traverson is superior, so why not extend it and actually turn it into a more full-fledged tool?

eepstein avatar May 06 '18 06:05 eepstein

I was hoping to use Traverson w/ MockMVC to simplify some testing, but with only GET support, I don't see how Spring's Traverson is of much use at all.

It feels somewhat misleading to call this "Traverson" at all. Inspired by it? Sure, minimally in its API design. But this is not at all the Java version of Traverson and it just becomes confusing by calling it such.

jamesdh avatar Nov 28 '22 19:11 jamesdh