Our OO-biased brains are trained to think in terms of classes and associated operations (Cart.order()) and it apparently takes a considerable amount of time for our brains to re-wire and think in terms of transferring representations to modify resource state.
As a result, people are tempted to come up with ways to map non-uniform operations onto HTTP's uniform interface. One offspring of such endeavor is the REST anti pattern of Action Resources.
I have not tracked it back to its origin, but the general form goes something like this:
Given an operation foo(), define a link semantic 'foo' that enables the server to tell the client what the URI is of 'the foo-action resource of some other resource R. Knowing the foo-action resource Rfoo, the client would then be able to invoke the foo() operation on R by means of an empty POST to Rfoo:
Find foo-action resource of R:
HEAD /items/56
200 Ok
Link: ;rel=foo
Invoke foo() on R:
POST /items/56/foo
Content-Length: 0
204 No Content
So, why am I calling it an anti pattern?
Action resources are an anti pattern because the approach violates REST's self descriptive messages constraint. How so? Because the meaning of the POST request depends on resource state at the time the client learned that /items/56/foo is the foo-action resource of /items/56. There is nothing in the request that allows the server to understand the actual intention of the client at the time the server handles the POST request.
Suppose the client issues the above HEAD request at time T1, the server replies at T2 and the client receives the response at T3. By the time T4 the client sends the POST request to the action resource (and T5 when the server actually receives it) the server might have changed and is now looking at the POST with the empty body which translates to the client intention of telling the resource /items/56/foo to process this [empty body].
The server does not know that the request semantics depend on the server state at T2 when the server created the HEAD response and therefore cannot detect any mismatch between client intention and its own interpretation.
Pure operations do exist. What do you do then? Get slapped by the REST police and lose the "REST" brand?
ReplyDeleteJust design the messages to communicate the user's intent. For example, instead of doing something like POST [empty] /carts/65/order POST .. to /order-processor. In the former request the meaning is just 'order whatever you currently perceive /carts/65 to be' while the latter contains, right *in* the message that the user wants to order a bunch of particular items.
ReplyDelete@Mike: it does not need to. At least not for the ordering itself. I guess it would compare the order to the user's cart (based on logged-in user ID) and empty the cart afterwards.
ReplyDeleteYou might also want to see: http://alandean.blogspot.com/2008/11/what-restful-basket-checkout-might-look.html
ReplyDelete