Re: Link Relations
Philippe Marsteau <[email protected]> Sat, 9 Nov 2013 19:14:48 -0500
| Newsgroups | gmane.comp.web.services.rest |
|---|---|
| Message-ID | <6547243972313371892@unknownmsgid> |
Thank you Mike. That clarifies a lot. I think I misunderstood link relationships vs. capabilities/states. Your proposed approaches help me see how to better design this. A key requirement for me is to reduce as much as possible coupling, therefore I try to design resources as generically as possible (a list of simple attributes and a list of relationships/states) with the goal to allow for maximum evolvability of the API - given the mostly UI-driven interactions against the API. Basically, I try to map the web pages one would interact with from a browser, but stripping out the UI elements (using generic JSON like format). By keeping the media type as low entry barrier (simple) as possible, assuming client will mostly render the data in its preferred technology, adding attributes or actions becomes highly dynamic without requiring consumer to "uptake" changes: attributes appear dynamically in UI front end and new interactions (think of "more actions" drop box) becomes added dynamically as well. I think your CJ media type is pretty generic too, so maybe this idea/goal is familiar to you... I also understand this might not fit for system to system type of interactions (scripted/automated integrations) and my goal might be too idealistic. Have you seen such type of REST APIs? Am I heading in the right direction? What about the others experience with forms resources vs strongly typed links? Phil Le 9 nov. 2013 à 18:51, mike amundsen <[email protected]> a écrit : <snip> Now how do I tell in this book representation that at this time, clearing the shopping cart or adding the book to the shipping cart is not allowed (eg based on authenticated user permissions) but reading it is allowed? I wish user could discover from the representation rather than having to call OPTIONS or learning after the fact (error message)... </snip> If you wish to communicate this level of detail to clients (not at all a bad thing) often people think of these as _actions_ instead of states and just communicate the possible action: rel="clear" rel="add-book" and so forth. I try to steer clear of that whenever possible (as a design goal) and express these things as "states" on the server that need to be communicated to the client. for example (just making this up here...): - "clear" (the resource can be cleared or removed) - "edit" (the resource can be appended-to or child records can be added) and so forth. this means representations can look like this: <shopping-cart> <link href="..." rel="collection http://example.com/rels/shopping-cart" state="read clear" /> <items count="9"> <item href="..." rel="item http://example.com/rels/book" state="read clear"> ... </item> ... </items> </shopping-cart> or you can use a much more explicit design: <shopping-cart> <clear href="..." rel="collection http://example.com/rels/shopping-cart" /> <read href="..." rel="collection http://example.com/rels/shopping-cart" /> <items count="9"> <item> <clear href="..." rel="item http://example.com/rels/book" /> <read href="..." rel="item http://example.com/rels/book" /> ... </item> ... </items> </shopping-cart> These are just two possibilities. Note that i didn't include a protocol method in these designs, but that would be possible, too. an explicit example (one that might support more than one protocol) might look like this: <shopping-cart> <clear href="..." rel="collection http://example.com/rels/shopping-cart" method="HTTP.DELETE"/> <read href="..." rel="collection http://example.com/rels/shopping-cart" method="HTTP.GET"/> <items count="9"> ... </items> </shopping-cart> Again, this is design so there are many possibilities. <snip> Also where in this context fit the concept of forms, allowing user to fill in some parameters... </snip> yes, i use forms quite often. this is about what state needs to be transferred from the client to the server (usually we only think about transferring state from server to client!). I might have a server that requires additional data in order to add an item to a cart: <link href="..." rel="http://example.com/rels/shopping-cart"> <data name="quantity" value="1" /> <date name="stockid" value="q1w2e3" /> <date name="required-delivery-date" value="2013-12-24" /> </link> and so forth. I am in the habit of including forms in responses[0]. However, some folks prefer to only include links to forms and keep the forms as stand-alone resources[1]. Still others think it best not to include this information at all and keep that information as part of the documentation[2] Again, these are design decisions you can make on your own when creating your own message format (media type) or one that you can use to guide which of the existing registered types will best fit your needs/aesthetics. Cheers. [0] http://amundsen.com/media-types/collection/format/#objects-template [1] http://iansrobinson.com/2010/09/02/using-typed-links-to-forms/ [2] http://tools.ietf.org/html/draft-kelly-json-hal-06#section-8.2 mamund +1.859.757.1449 skype: mca.amundsen http://amundsen.com/blog/ http://twitter.com/mamund https://github.com/mamund http://www.linkedin.com/in/mamund On Sat, Nov 9, 2013 at 5:46 PM, Philippe Marsteau <[email protected]>wrote: > Interesting... > > Now how do I tell in this book representation that at this time, clearing > the shopping cart or adding the book to the shipping cart is not allowed > (eg based on authenticated user permissions) but reading it is allowed? I > wish user could discover from the representation rather than having to call > OPTIONS or learning after the fact (error message)... > > Also where in this context fit the concept of forms, allowing user to fill > in some parameters, before user can actually add the book in the shipping > cart (eg, number of books to add)? Would the representation include a link > to the form (instead of to the shopping cart directly), and its doc states > only GET is allowed? The idea is to let user discover which attributes are > need as input before a PUT (or POST or PATCH) can be called on the shopping > cart... Instead of having client to hard code editable input fields to be > requested to user ("knowing" the media type or profile of the shopping cart > resource). > > Thanks again, it helps. > > Phil > > Le 9 nov. 2013 à 16:53, mike amundsen <[email protected]> a écrit : > > FWIW, you're getting in to "design" space here - and that's based on > context and preference. nothing right/wrong here so there are lots of > options. > > first, i usually indicate state properties of a resource using data > elements in the representation, not transition elements: > > <book> > <in-stock value="true" /> > <link href="..." rel="http://example.com/rels/shopping-cart" /> > </book> > > again, instructions on the link identified as the shopping cart might look > like this: > - HTTP.GET returns the state of the shopping cart > - HTTP.POST adds the current book to the shopping cart > - HTTP.DELETE clears all items from the shopping cart > and so on... > > now clients (humans) can see that the "state" of the book is "in-stock" > and then decide to take an appropriate action. > > > as for "I believe there are cases where the server dictates the steps > before"... > > yes, the server may have rules about what "state" server-side resources > need to have before a task can be executed. This can be viewed as dictating > that "state" of things on the server, not dictating the order in which > things happen on the client. This POV is close to the way programmers had > to (re)learn to design user interfaces with teh advent of the pointer > device (mouse). Suddenly, users could not be "led" from input to input in a > certain order. Users had be power (and audacity) to click around on the > screen, enter things in various order and so on. It was bedlam (grin)! > > eventually, we learned to build UIs that used things like progressive > disclosure, disabling items until certain "state" in the UI is achieved, > etc. > > we need to do that same for hypermedia services on the web. > > hope this helps. > > > mamund > +1.859.757.1449 > skype: mca.amundsen > http://amundsen.com/blog/ > http://twitter.com/mamund > https://github.com/mamund > http://www.linkedin.com/in/mamund > > > On Sat, Nov 9, 2013 at 3:25 PM, Philippe Marsteau <[email protected]>wrote: > >> Appreciate the feedback and experience sharing. >> >> So reusing my use case if buying a book, what rels would define from the >> root book collection resource? (assuming the application is designed to let >> customers buy books). >> >> How do I let the consumer discover a book listed in the collection can >> now be "bought"? >> >> I believe there are cases where the server dictates the steps before a >> book order can be placed: server decides shipment info is ended or payment >> info is needed. I mean the book listed in store does not have a model >> relationship "orders" linking to it, does it? >> >> You cannot create an order until user goes through a server defined list >> of steps. Furthermore, the steps could be different per user (eg one who >> already stored his payment/shipping on file for future orders). >> >> While I completely understand it is the consumer who activates the >> hypermedia controls, and thus the workflow progress depends on the user, I >> need a way to let consumer discover through hypermedia controls "what" can >> be done at each step of the application business workflow (here: what info >> must be entered to complete the book order process?), based on user >> permissions or internal application state... >> >> Your further guidance is appreciated! >> >> Le 9 nov. 2013 à 14:25, mike amundsen <[email protected]> a écrit : >> >> I will say that i've gone both routes (using rels to indicate >> relationships and using rels to indicate actions) and am not settled on >> either. >> >> the "rel" community def. wants to see this attribute used to indicate >> relationships. reviews of recently registered values at the IANA show this. >> >> however, i can see the appeal and value of having action indicators on >> hypermedia controls; esp. in cases where machines are doing the work of >> selecting controls to activate. in this case it seems efficient to reduce >> the "decision distance" of 1) find the control that has an id of the >> desired target then, 2) look at the control to see what protocol action is >> available to 1) find the control that has the id of the desired action of >> the target. But this is, in the long run, a false efficiency. It _assumes_ >> the client code already "knows" things (action and target are coupled) and >> constrains the possible options for the client ("you can only do a single >> action for this control, want to do some other action? sorry, no control >> for that here, move along"). >> >> in the big picture, i've found keeping target identifiers (collection, >> storage, document, person) decoupled from action (share, modify, copy, >> move, approve, cancel) is a big win. while it adds some >> indirection/complexity to the representation (both at design-time and >> run-time) this pattern also adds more options and increases the >> independence of the client application. including allowing clients to (in >> some cases) create new successful workflows that the server didn't map out >> even though it is completely allowed by the state machine. >> >> FWIW, if you want to continue to constrain clients to only following >> strict server pre-defined paths, you can still do that while sticking to >> the "rel is for relationships" pattern. >> >> Cheers. >> >> >> >> mamund >> +1.859.757.1449 >> skype: mca.amundsen >> http://amundsen.com/blog/ >> http://twitter.com/mamund >> https://github.com/mamund >> http://www.linkedin.com/in/mamund >> >> >> On Sat, Nov 9, 2013 at 12:59 PM, Philippe Marsteau <[email protected]>wrote: >> >>> I see 2 distinct purposes of link relations: either to qualified a >>> transition from one state to another of the resource, or to describe how >>> two resources relate one to another. >>> >>> This discussion I think focused on the latter. I am specifically curious >>> of best practices for the former case, when a RESTful API aims at letting >>> consumer work through a specific workflow (eg. buying a book online). >>> >>> I thought the best practice was to let user land ton an entry point >>> resource (eg collection of books) and then let user evolve in the workflow: >>> first by affording user to initiate the workflow (eg. "rel=buy" which >>> likely translates with GETing a "buy-a-book-form" resource, letting user >>> discover which inputs are need to start the workflow). Then subsequently, >>> each step in the workflow will afford user to confirm an order, select >>> payment information, shipping details... Ultimately the server will confirm >>> creation of an order resource (and maybe provide a shipment resource >>> allowing user to track shipping status or to cancel order, etc.) >>> >>> In such typical workflow scenario, is it a bad practice to expose rels >>> as "actions" (thus verbs)? I think of having server sending relevant >>> actions on each step (as part of resource representations), letting user >>> discover HTTP methods and target resource to interact with as a result of >>> activating the hypermedia control (action). >>> >>> In the example of AtomPub, we have a similar hypermedia control "edit" >>> (verb) to afford atom consumer a given feed entry can be edited. Which >>> translate with a PUT to the target href (the target feed entry). >>> >>> In other words, what is the best practice to express hypermedia actions >>> in a RESTful way, to allow consumer to control the workflow while the >>> server controls the affordances of the user (based on internal application >>> state)? >>> >>> Phil >>> >>> Le 8 nov. 2013 à 02:58, Mike Kelly <[email protected]> a écrit : >>> >>> >>> >>> On Fri, Nov 8, 2013 at 1:31 AM, Jan Algermissen >>> <[email protected]> wrote: >>> > Hi Mike, >>> > >>> > On 08.11.2013, at 02:08, mike amundsen <[email protected]> wrote: >>> > >>> >> >>> >> not sure i understand the Q, but i'll offer this: >>> >> >>> >> rel="http://example.com/rels/publisher" describes the relationship >>> between the source and the target. >>> >> >>> > >>> > I like to try to emphasize what the target is *to the source* with the >>> goal that the application-level effect of the HTTP methods falls into place. >>> > >>> > This IMO helps a great deal with avoiding to layer specialized >>> application protocols on top of HTTP (which already is the application >>> protocol). >>> > >>> > IOW, it helps prevent redefinitions of the meaning of HTTP methods. >>> POST means POST, it cannot mean 'publish the source resource'. DELETE means >>> DELETE, it cannot mean 'unpublish the the source resource'. >>> > >>> >>> Well, those methods have a general meaning within the uniform >>> interface of HTTP whose purpose is to add to the self-descriptiveness >>> of messages and, in doing so, to afford intermediation across the >>> system (e.g. web caching). The HTTP method definitions attribute >>> meaning designed for this purpose (e.g. establishing safety, >>> idempotency, cacheability, etc). >>> >>> Provided the link relations are not in conflict with the HTTP >>> definitions, and are merely qualifying the details of methods within >>> the context of a given transition, then it is wrong to think about >>> that in terms of "redefinition". It's qualification. >>> >>> In practice, it's much easier for consuming parties if your >>> documentation is specific by providing an explicit description of the >>> meaning and structure of the various requests possible over a given >>> link. Leaving your documentation so abstract that the reader is left >>> with the task of inferring every part of each possible request does >>> not seem like a very pragmatic approach for custom link relations (but >>> may be more appropriate for standardised link relations). >>> >>> > If you find yourself in a situation that you absolutely must tell the >>> client developer this, rephrase the hypermedia semantic (here: the link rel >>> spec). >>> > >>> > There is nothing to say againts hints regarding the intended >>> 'canonical' use case but I can always only be a hint. AtomPub is an >>> example, where the spec tells us so much about the interactions between >>> client and server that it looks like a protocol when it is actually only >>> hints about a canonical application flow. Focussing on resource semantics >>> would have been much nicer, IMHO. >>> > >>> > One simply cannot constrain HTTP servers that way and still have REST. >>> > >>> >>> The importance of HTTP methods from a REST point of view is that they >>> create **some** visibility of the client server interactions, so that >>> the messages can be understood to _a certain extent_ by >>> intermediaries. Provided that visibility is not impacted (i.e. a link >>> rel's qualification of a method doesn't _conflict_ with HTTP's) then >>> how does this have any bearing on the "RESTfulness" of the >>> application? >>> >>> Cheers, >>> M >>> >>> >>> >> >