Re: RESTful order-status API (was: URI design, part 2)
"Eric J. Bowman" <[email protected]>
| Newsgroups | gmane.comp.web.services.rest |
|---|---|
| Organization | Bison Systems Corporation |
| Message-ID | <[email protected]> |
+1 to the other answers you've gotten. Except... REST is about optimizing the hell out of GET. The hypertext containing the PUT control is one place to GET the order status. But, why cache- expire the entire record when only one string is changed, multiple times after the order is placed and becomes static? A RESTful order-status API should separate the dynamic aspects of order processing from the static, as sub-resources, and manipulate *those* to alter a dynamic representation of the static order. This becomes especially efficient when, say, a CC is rejected and the customer needs to enter another one. Consider PUT /orders/1/status with strings like placed, processing, pending, and the tracking # from the shipper -- I'd even consider application/xml and application/json acceptable media types for a snippet like this, of course not for the hypertext control defining the PUT. I'd never PUT 'canceled', I'd use DELETE as Jan described, which would trigger a reshelving-fee transaction, with /status returning reshelving on 200 OK, before /orders/1* return 410 Gone, indicating the transaction has been fully reversed including by the inventory system. Using code-on-demand to fill in the current status on the PUT control exposes a status API which may be utilized many different ways (push, poll, etc.), allowing for serendipitous re-use. The downside of being an additional round-trip is mitigated by using compression such that the /status 200 OK response fits in one IP packet. Note that XForms may be used to make this code declarative, avoiding the optional constraint. This thread isn't about URI design at all, in fact it's irrelevant to this discussion about hypertext-driven application state, as is method selection. Also RESTful: /CRMapp?order=1&query=status on GET, and /CRMapp?order=1&status=canceled on POST using application/x-www-form- urlencoded, if we assume the hypertext constraint is met, which is what this thread is really about. Then we can discuss the pros and cons of various media types which can implement a RESTful status API, regardless of how the shopping cart is implemented. If you're working with making a legacy system more RESTful over time, you may want HTML 4, JS and POST. If this is greenfield, you may consider XForms w/ PUT and DELETE. Or, use HTML 5 if this is a Web system, not sure where it is regarding PUT/DELETE, but it really doesn't matter... The key is the architectural consideration of using subresources for dynamic elements like order status, allowing the order itself to become sticky in the client-side cache, while also allowing manipulation of that resource to occur in one-IP-packet round-trips. Optimizing PUT/POST/PATCH doesn't amount to much in the grand scheme of things, what counts is optimizing GET by making static all those bytes which make up the order being processed, and manipulating its subresources. The hypertext interface doesn't even have to reflect the strings in /status, it could be a graphical progress bar followed by e-mailing the tracking number (instead of, or in addition to, displaying it). Or, the strings in /status 200 OK could be numerals, whose semantics are conveyed by the PUT control or other hypertext conveying order status. Always remember REST is an architectural style, not implementation guidelines. If you take one thing from it, it should be "optimize GET to maximize caching." Then, any implementation mistakes you make are correctable down the line, instead of coming here and being told to go back to the drawing board -- iow, if you've separated static from dynamic as an architectural pattern, then we can make changes to URIs and methods based on what media types are most appropriate for your application, because that'll be bikeshedding if you get your resources right. I prefer developing REST systems in XForms, makes it easy to separate static from dynamic in declarative code, to get a handle on what your resources *are* and how they relate to one another. I call this hypertext-constraint-centric development. The result is a hypertext API which may then be implemented any way it needs to be, letting the implementation requirements dictate the system's ultimate hypertext, URI allocation scheme, and media types if (most likely) XForms isn't appropriate. I may hate my HTML 4 implementations' URIs and methods, but the underlying systems are implicitly RESTful and thus easy to upgrade over time, as new hypertext technology emerges and matures. -Eric On Fri, 30 Nov 2012 10:45:26 -0800 Erik Wilde <[email protected]> wrote: > +1 on this, it probably would be a good mapping of domain > interactions to HTTP verbs. > > On 2012-11-30 10:43 , Jan Algermissen wrote: > > > > On Nov 30, 2012, at 7:08 PM, Nicholas Shanks > > <[email protected]> wrote: > > > >> On 30 Nov 2012, at 13:15, Max Toro wrote: > >> > >>> Thanks for your answers, it's pretty much what I had in mind. > >>> > >>> I want to discuss a second example: > >>> > >>> a) > >>> POST /orders/1/cancel > >>> > >>> vs. > >>> > >>> b) > >>> PATCH /orders/1 > >>> > >>> canceled=true > >>> > >>> > >>> Does REST say anything in favor or against these two designs? > >> > >> REST says "Do 'b', never 'a'." Sorry! > > > > Yes, right. > > > > If it suits your use cases, consider: > > > > DELETE /orders/1 > > > > Which might well result in the order being moved to a > > cancled-orders collection. IOW, it need not be erased entirely. > > > > Jan > > > > > > > > > > > >> The simple rule is URIs are for nouns, HTTP methods are for verbs. > >> > >> You could get away with this though: > >> > >> POST /orders/1 > >> cancelled=true > >> > >> Originally, POST was intended to mean "post a reply" the same as > >> it's NNTP namesake/predecessor. Now, though, the authors of HTTP > >> concede that it's modern meaning is "Hey, server, use these data > >> (request body) to perform some action to this resource (uri)" > >> > >> As such, by POSTing to /orders/1 you are at least getting the > >> resource part of the API right, even if you are lacking the > >> semantics of a PATCH request. > >> > >>> Personally, I would never do 'b' because it's simply hard to > >>> implement with the tools I use. Also, isn't it a case of > >>> tunneling? 'Cancel' is an action that does more than simply > >>> update a resource. > >> > >> > >> I wouldn't call it tunnelling, tunnelling would be something like: > >> > >> POST /orders/1 > >> > >> _method_override="DELETE" // could also be custom HTTP header > >> > >> If the "cancel" action is just updating a resource state, rather > >> then, say, DELETEing the resource, then you could even do > >> something like: > >> > >> PUT /orders/1/cancelled > >> true > >> > >> (again, use POST if you can't PUT) > >> > >> and correspondingly: > >> > >> GET /orders/1/cancelled > >> > >> => "true" > >> > >> GET /orders/2/cancelled > >> > >> => "false" > >> > >> (or 1/0, yes/no, … however you wish to represent it) > >> > >> > >> For reference, stackoverflow.com is a good place to go with these > >> sorts of questions. Many have already been asked in various forms, > >> you'll find the answers already provided. > >> > >> — Nicholas. > >> > >> > >> ------------------------------------ > >> > >> Yahoo! Groups Links > >> > >> > >> > > > > > > > > ------------------------------------ > > > > Yahoo! Groups Links > > > > > > > > -- > erik wilde | mailto:[email protected] - tel:+1-510-2061079 | > | UC Berkeley - School of Information (ISchool) | > | http://dret.net/netdret http://twitter.com/dret |