anybody doing non-trivial things with REST sooner or later runs into interactions beyond the simple CRUD (create/read/update/delete) operations. there often are cases where operations might be tied to a specific resource (or mainly to that resource), and then the question is how model this in a RESTful way. a pattern that is seen frequently is the action URI
, which is a URI that specifically represents one action on one resource.
for example, if there is an open order http://example.com/order/42, then the payment action
will be represented at the URI http://example.com/order/42/payment. clients will interact with that by using either PUT or POST (PUT seems to be the preferred way) to submit a payment.
this clearly works, as demonstrated by many existing APIs, but is it really the best or only way of doing it? there are some issues with this design:
- no linking: if this is just a payment service, why not use
http://example.com/order/paymentinstead and have a payment media type that links to the order being paid? that would not only make the payment resource a more reasonable interaction point (it's basically like a cashier accepting many different things to be paid for), it also would allow for richer functionality such as paying for multiple orders (simply link to all the orders you're paying for) or even paying for third-party orders (simply link to these 3rd-party orders). - contrived resource model: if the action indeed is bound to a single resource (in contrast to the potentially more general action mentioned in issue 1), then why is it a resource? it seems that the interaction taking place is to submit a state change to the actual resource, and then that resource is changing state (from
awaiting payment
topaid
) as a result of that interaction. what is the reasoning behind turning the payment into an action, and why is it significantly better than the dreadedjust embed
anti-pattern?action=paymentin URI query parameters - not media type centric: if payment is done using a payment request, then there has to be a self-describing document conveying the payment data. this could be submitted to a general payment resource (as described in issue 1) or to the resource itself (as described in issue 2), but there really does not seem to be a good reason why it would need to be submitted to a specific URI just minted for that particular operation on that particular resource.
please keep in mind that even if you would use a general-purpose payment URI or POST a payment to the order URI, clients would still only be linked to the payment URI when payment would be a state change permitted by the server. as usual, a rel="payment" link would only be included if paying was an option, and the only difference to the resource-specific action URI approach would be that it would point to either a general-purpose payment URI, or to the URI of the order accepting the payment media type.
after a quick but non-representative look at some books and APIs, it seems to me that the resource-specific action URI is a pretty common pattern, and i would be interested in opinions about the alternatives, and also whether people have looked at all these patterns and have made decisions between them because of constraints that made one pattern a better fit that the other. as usual, there are many ways to solve a given problem, but the resource-specific action URI may be one pattern that could be replaced by others, at least in some scenarios.
Let me address your points in reverse order:
3. This could be easily alleviated by including a link in the order's representation (something like link rel='payment'), so it's orthogonal to the other aspects.
2. The reason many people don't use a state change on the parent resource is that they'd need a partial update.
1. I agree this is often a better option, and I share many of your concerns regarding action URIs. Personally, I use this pattern only if they feel natural, i. e. I can convince myself that there is other something that deserves to be its own resource, and naturally should be hierarchically “under” the parent resource. A key indicator to me is that I can find a reason to do a GET on this resource, too.
Posted by: Stefan Tilkov | Wednesday, December 07, 2011 at 23:46
I personally believe that this pattern, that I call 'link-rel-action', is really just RPC - the verbiness of the URL gives that away! Plus I also agree with Stefan, that a good rule of thumb is to ask what you can GET from such URLs.
There's a wonderful chapter in that excellent book .. what's it called? Ah yes, "REST: From Research to Practice" .. there's a chapter in there about a REST pattern or model called "FOREST"*, which itself talks about orders and payments and so on.. :-)
In FOREST, the author, Duncan Cragg, suggests POSTing Payment objects directly to their corresponding Ticket objects, where a Ticket is a server-side representation of a client's submitted Order. Like those slips you get in restaurants.
Further, you know when you can pay because of the state of the Ticket, no link-rel necessary (it would always point to the Ticket anyway!)
In fact, he also suggests a more peer-to-peer approach, POSTing updates on these Orders to these Tickets - containing new links to Payments hosted 'client side', which a Ticket object can GET from the client at its leisure.
Cheers!
* http://www.springerlink.com/content/v454gmw41411m061/
Duncan
Posted by: Duncan-cragg | Thursday, December 08, 2011 at 15:16
duncan, it's quite a conincidence that i have a couple of copies of this book just laying around... it's of course nice to see somebody reasoning very similar to the thoughts i was having, but let me step back a little. you identify the "verbiness of the URI" to be a bad sign, and i think that's my main concern, too. subbu in his cookbook in recipe 2.6, on he other hand, explicitly recommends to use "Controller Resources", and his main objection about the approach of POSTing to the URI of the actual resource is that then the POST request body would contain the verb, so he claims that the "verbiness of the representation" is a bad thing. i guess in the end the verb needs to go somewhere, since the operation is not directly part of the uniform interface, and REST only has so many places where you can stick it.
personally, to me it seems that sending such a request as a self-describing representation in a request is the cleaner way to go, because you are interacting with the resource (or, as suggested, maybe with a more generic payment resource that would allow payment for a variety of things, all of which would be linked). but for being self-describing, the payment definitely would need to have a link to the order being paid. but apart from the design option of decoupling the payment resource from the paid items, i am having a hard time coming up with actual reasons to go one way or the other. it just seems more natural to represent the operation in a self-describing message, in the same way as you would have filled out a form to initiate an action on a pending business process in old-school paper-driven processes, and there the interaction point would have been the pending business process, and not an endpoint specifically created for this one possible action. but still, this is mostly a gut feeling, but maybe that's all there is in this case.
one last remark: you say "you know when you can pay because of the state of the Ticket, no link-rel necessary (it would always point to the Ticket anyway!)", but i don't quite get that. how do you represent the state and detect the fact that it's ready to accept payment? isn't one of the fundamental principles of REST that such a state change should be driven by hypermedia controls, and thus a state change would be exposed as a link a client can follow? that was my assumption, but it seems that you have something else in mind. how do you represent the state change in the resource?
Posted by: dret | Friday, December 09, 2011 at 09:55
stefan, thanks for the comment. i think what you're saying in point 3 is what i was suggesting, so we're in agreement. about point 2 i am wondering whether the desire to make a partial update is the main issue here. you can make partial updates by POST or PATCH (which is what i am suggesting), but more importantly, you're not really "updating" the resource, at least that's not my understanding of the semantics. you're transferring information to the resource that will cause it to change state, and that information should be self-describing. it's like turning in a payment stub in a restaurant. maybe you pay with your waiter (he may be the "order-specific payment point") or with the check-out guy (who will need a link to the order to make sense of your request to pay), but in both cases you're initiating a state change that, should it succeed, will change your order to change state. essentially, the payment processor then will update your order state from "open" to "paid", but that's not what you do as the one initiating the payment.
and i think that's pretty much my response to your point 1, too. payment and a paid order are different things, and may even be managed by different authorities. if they do, there should be a payment resource somewhere that accepts payments that link to orders. but should you decide to combine payment and order management into the same authority, then payment becomes just a new interaction that is supported on an order, and as a result will, if it is accepted, change the state of the order itself. i don't think that the action URIs often allow GET, but i may be wrong.
Posted by: dret | Friday, December 09, 2011 at 10:06
in cases where we expect the client to recognize, parse, and activate" state transitions, they will need to be labeled consistently. designs can do this in various ways: [create-customer href="..." /], [form class="create-customer" action="..." /], {"create-customer" : {"href=" : "...", ... }}, etc.
these are all examples of "affordances" in the response; they "afford" the ability to create a customer. in my experience, it is much preferred to include self-describing affordances in the response rather than only a URI.
Posted by: mamund | Friday, December 09, 2011 at 11:02
Assuming that an order payment is desirably an idempotent operation, using a resource specific payment URI ("http://example.com/order/42/payment"), with the PUT method, would enable this property. Isn't this a concrete advantage of the "payment action".
Posted by: Pedro Félix | Friday, December 09, 2011 at 14:28
maybe the most interesting question is not so much that of the "Action URI" identifying the "Controller Resource", but whether the interactions are designed in a way so that there is no hidden context. if the payment representation submitted when following the payment link is self-describing (i.e., the payment identifies the order it is for by linking to it), then in fact it doesn't matter whether the payment URI is a subordinate of the order URI, the order URI itself, or a completely different URI. this also means that the whole interaction pattern works independent of the specific URIs being used, and that in fact might be the most important thing to look out for: there should be no "context creep" from URI structure to the way how interactions are being interpreted. is that a conclusion that others might be willing to subscribe to as well?
Posted by: dret | Friday, December 09, 2011 at 18:33
felix, payment is not something that for business transactions should be considered idempotent. for sellers "idempotent payment" may be desirable (they happily accept repeated payments), but for buyers, they really only want to pay once, and if they pay more than once, that still buys them the thing, but not in way that is very advantageous for them.
Posted by: dret | Friday, December 09, 2011 at 18:39
1) I disagree: a payment system should ensure that a customer is only credit *once* for the *same* order, even if the seller receives multiple payment "messages" (e.g. customer retries in the event of failure). Using PUT would allow an HTTP intermediary to have this retry behavior automatically. Also, this idempotency characteristic would not have to be communicated out-of-band. It would be implicit by the use of the PUT method.
2) I agree that the payment representation should be self-describing and there should be "no context creep from URI structure". Namely, I agree with Amundsen that "self-describing affordances [should be] in the response". IMHO, this isn't incompatible with the use of PUT and "http://example.com/order/:id/payment".
Posted by: Pedro Félix | Saturday, December 10, 2011 at 03:33
> you say "you know when you can pay because of the
> state of the Ticket, no link-rel necessary (it would
> always point to the Ticket anyway!)", but i don't
> quite get that. how do you represent the state and
> detect the fact that it's ready to accept payment?
Well, following the logic of this in steps: take out the redundant href, giving you [link rel="payment" /], which appears when it's possible to pay. Converting to a JSON representation, that could be { .. "payment": true .. }, or { .. "status": "payable" .. }. Just something about the state that indicates payability - in fact, it needn't even be overtly explicit like this.
> isn't one of the fundamental principles of REST that
> such a state change should be driven by hypermedia
> controls, and thus a state change would be exposed
> as a link a client can follow? that was my assumption,
> but it seems that you have something else in mind.
> how do you represent the state change in the resource?
Well that's the crux of the difference in thinking between my view of REST when applied outside of the normal document/browser Web, and that of the "link-rel-action" advocates! I go into excruciating detail on this subject in my description of FOREST, but I'll try to distill it a bit for this discussion... :-)
First, we've got to disentangle the two state systems: the resource or server state and the application or client state. Because POST isn't affected by the Hypermedia Constraint.
The Hypermedia Constraint describes the way that the state of a client is supposed to be constrained and guided by hyperlinks in the state of the server. This constraint thus applies to the GET side of REST. Indeed, links that you can jump, and GET, and cacheing, are the bulk of the subject matter of REST.
If it's a GET, the /client state/ changes. If it's a POST, the /server state/ changes!
You can usually then see the effects of your POST in the stuff you then GET: for example, if you were redirected to a resource after the POST. So that makes it look like the POST drove the client application state, but it didn't. That's still GET-side stuff.
So with this model, it doesn't make sense to manifest POSTability with a link that you POST to. Links are only for GET, for describing the hypermedia/hyperdata graph, for moving on /client/ application state.
To move /server/ resource state on, you POST to the resource - the GET-able resource! - that you're interacting with, that the documentation says would be interested.
Like you said, this means moving the 'verb' - or the 'intent' or the 'declaration of interesting client application state that may affect the server resource state' - into the POSTed content. You document that, when you see a server resource in 'this' state, it means you're good to POST your 'interesting client state' or 'action' (ugh) to it - and watch it change accordingly. This is a fundamentally declarative model, into which actions and verbs and imperative interactions have to be contrived.
REST is fundamentally declarative, is my claim.
That's my own re-interpretation of REST for machine-to-machine scenarios. Scenarios for which REST was not originally created, of course..
Posted by: Duncan-cragg | Sunday, December 11, 2011 at 14:51
hey duncan, thanks for the explanations. i am not quite sure i am buying it, though. if i have and require payments to be self-describing (i.e., link to the thing they are a payment for), then i can simply change that to and things will simply still work. meaning that if server state changes become more complicated than just affecting one resource, i can still handle that without having to change my order resource model. you would need to change the order model (and that would, btw, be a breaking change) if you had to make this change.
in our scenarios, many (in fact most) operations affect more than just resource, and thus we often have these "external links", often to processes. if you want to trigger some operation on a resource, you have to kick off a complete process, which in itself is a resource and, if it successfully completes, will eventually change the state of the resource that originally linked to the process. assuming that all resources are "self-contained" in the way that all interactions are just "running on that resource" would be way to restrictive. so while we might want to use the pattern for very simple interactions (such as updates), most interactions with resources will be more complicated than that and we need the ability to decouple the resource from the process that may use the resource and/or change the state of the resource.
Posted by: dret | Wednesday, December 14, 2011 at 17:54
Well I think we're in violent agreement about a lot of this..!
I think we both agree that the payment POST body should be self-descriptive rather than depending on round-tripping information in an opaque, server-only payment link. In other words, the body representation needs two important elements: (1) an indication that this is a Payment, and (2) a link to the Order to which it applies.
This eliminates the significance of the "/order/42" and "payment" information encoded by the server inside your "http://example.com/order/42/payment" example, allowing us the freedom to POST the same body to resources other than per-resource, non-GET-able ones: such as the order itself, or a resource for processing payments.
It also allows us to inspect and understand the message body, without needing to dig into the server's link, etc. You may consider whether this means the Payment is also declarative and - horror! it's a POST! - idempotent ... ! :-)
Posted by: Duncan-cragg | Monday, December 19, 2011 at 12:54
Next, I think you're saying "what if you want to add the ability to pay for several orders at once?" Your resource and interaction model has a layer of indirection via a link-rel to which we must POST the payment. This can be set to the order itself, but can be set later on to a "payment processor resource", to add multiple order payment functionality, without breaking single-order paying clients. (I don't know if you can GET your payment processor resource?)
On the other hand, my Payment POST was defined/documented as being sent directly to the Order (Ticket). Clearly, a link-rel to a (GET-able!) resource that handles payments could be built in to my resource interaction model instead. This link could even be added only when payment was possible.
But that would be nothing to do with satisfying REST and the Hypermedia Constraint; just a feature specific to this domain, to this resource and interaction model. And you don't need a link just for every POST you may want to do! That would be building in too much indirection "just in case".
Instead, look at your domain or resource model for GET-able links to real domain resources. My Orders (Tickets) have links to their "Dealer" object - which creates Tickets and holds lists of them. I could simply say I now allow multiple payments to be sent to that Dealer.
Posted by: Duncan-cragg | Monday, December 19, 2011 at 12:59