Re: Link Relations
mike amundsen <[email protected]> Sat, 9 Nov 2013 20:25:47 -0500
| Newsgroups | gmane.comp.web.services.rest |
|---|---|
| Message-ID | <CAPW_8m4DmN1c_Tp1YqL0VKX1uPdW74LQgyZ-1V9wghQCQ52X=g@mail.gmail.com> |
<snip> 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. </snip> If you favor JSON and want to reduce coupling between internal coding and the shared messages, I highly recommend one of the recently-registered hypermedia types such as HAL+JSON[1], Collection+JSON[2], and Siren[3]. I find each of these has a unique strength and all of them do a good job of leading you toward SoC between local components and shared state messages. By treating the message as a structured format independent of your problem domain (books, etc.) you get quite far down the path of decoupled communications. HTML has been successful at this for more than a decade; our servers continually transform local business objects in the this format and enable applications running in a client app that knows nothing of the problem domain, but *does* understand the message format and the protocol details express _within_ the message (HTML.A, HTML.IMG, HTML.FORM). <snip>What about the others experience with forms resources vs strongly typed links?</snip> Yes, this convo has gotten a bit narrow since I am dominating the thread. I know there are several others here who have experience in this space, too. Cheers. [1] http://stateless.co/hal_specification.html [2] http://amundsen.com/media-types/collection/ [3] https://github.com/kevinswiber/siren 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 7:14 PM, Philippe Marsteau <[email protected]>wrote: > 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 >>>> >>>> >>>> >>> >> >