Re: URI design, part 2
"Eric J. Bowman" <[email protected]>
| Newsgroups | gmane.comp.web.services.rest |
|---|---|
| Organization | Bison Systems Corporation |
| Message-ID | <[email protected]> |
Max Toro wrote: > > Did not choose DELETE because cancel does not delete the resource, it > executes some logic which in the end sets it's status field to > Canceled. > DELETE /orders/1 doesn't have to delete the resource, it can move it to, say, /canceled/1. In which case you're only changing one property of the order "object" on your server -- its mapping. REST isn't CRUD. In a hypertext API, it's often best to have different URI paths for the same set of server objects, if their policies vary based on a property like status... Web servers configure policies based on path, so add another URI mapping instead of making server logic more complex by trying to apply different policies based on parsing content for 'canceled=true'. Try to think in terms of hypertext applications instead of serializing objects to hypertext -- status isn't a field in a hypertext document in REST when its semantics overlap that of HTTP status responses, especially if status varies by user role: The customer checking /orders/1 knows they've successfully canceled it, because their DELETE request responded 200 OK with the order and new status in the message body, and that URL now responds to GET with 410 Gone. The 410 response may include the order as its entity, or not, for the customer role. Other user roles, i.e. admin, may get redirected to /canceled/1, where they are subject to different policies than exist for an active order. Admins may DELETE from /canceled to actually delete a canceled order, while customers are 403 Forbidden from entering /canceled to begin with. Also, just because you're using the DELETE method, doesn't mean the UI has to say "delete" on the cancel control. > > The implementation of PATCH with a body 'status=Canceled' can be > tricky if you also accept changes to other fields, which may or may > not have some logic associated to them. > What matters is user intent. Clear intention to cancel an order should unambiguously be its own operation from the UI-design perspective; from the protocol perspective, this idempotent user action should be made explicitly visible on the wire by selecting the most appropriate HTTP method. Of all manipulations we may allow for an order, this is the only one that's self-explanatory without transferring a representation, another indication that DELETE has the semantics we're after, provided we don't get hung up on having to delete something -- which we don't! If, to the requesting user, canceling an order makes it go away, then using DELETE meets the self-descriptive messaging and uniform interface constraints of REST. What happens to the order is an implementation detail, hidden behind the uniform interface. To the world-at-large, the traffic pattern of an order cancellation looks like exactly what it is, as the principle of generality has been followed. The visibility of DELETE allows intermediaries to mark cached copies of /orders/1 as stale. This optimization is built-in to the deployed infrastructure of the Web, all it does here is ensure the requesting user doesn't re-load a stale copy of /orders/1 which fails to reflect the results of the action just taken. This can't be done with PATCH, even if you can get close by marking the request as idempotent. -Eric