Using Typed Links to Forms

September 2nd, 2010  |  Published in REST, REST in Practice by Ian Robinson  |  7 Comments

Nowadays, I tend to use a typed link leading to a form, rather than a heavily typed link alone (I’ll explain what I mean by heavily typed link shortly), to advertise unsafe operations and/or requests that require an entity body. Here’s an example of a typed link:

//Request
GET /shop HTTP/1.1
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Date: Mon, 26 Jul 2010 10:00:00 GMT
Cache-Control: public, max-age=86400
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<shop xmlns="http://schemas.restbucks.com/shop">
  <link rel="http://relations.restbucks.com/rfq"
        href="http://restbucks.com/request-for-quote"
        type="application/vnd.restbucks+xml"/>
</shop>

The link here is typed with the link relation value http://relations.restbucks.com/rfq, which indicates that the link points to a resource where a request for a quote can be submitted. Following the link, the client retrieves a form:

//Request
GET /request-for-quote HTTP/1.1
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Date: Mon, 26 Jul 2010 10:00:05 GMT
Cache-Control: public, max-age=86400
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<model xmlns="http://www.w3.org/2002/xforms"
  schema="http://schemas.restbucks.com/rfq.xsd">
  <submission
    resource="http://restbucks.com/quotes" 
    method="post" 
    mediatype="application/vnd.restbucks+xml"/>
</model>

The response entity body comprises an XForms form model. (Our custom media type definition for application/vnd.restbucks+xml says that one of the things a client can expect to receive in a response is an XForms form model.) The form’s <submission> element includes several pieces of control data: it indicates which verb to use when submitting the form (POST), where to submit the form (http://restbucks.com/quotes), and which content or media type to use when submitting the form (application/vnd.restbucks+xml). Because the definition of our custom media type includes more than one XML schema (much as the Atom specification defines two schemas, one for feeds and one for entries), the form’s control data needs to further clarify what /quotes expects to receive in a POST request. To clarify which schema the POST request body should adhere to, the <model> element’s schema attribute references the rfq.xsd schema.

Here, then, we have all the information a client needs to construct and submit a valid request to the /quotes resource. And all without any fields for the client to fill out.

Heavily typed links

A heavily typed link is one where the link relation describes not only the relationship to the linked resource, but also the HTTP idioms – the control data – necessary to manipulate that resource.

Using a heavily typed link our shop could link directly to the /quotes resource, instead of to a form:

<shop xmlns="http://schemas.restbucks.com/shop">
  <link rel="http://relations.restbucks.com/quotes"
        href="http://restbucks.com/quotes"
        type="application/vnd.restbucks+xml"/>
</shop>

Here, the definition of the link relation http://relations.restbucks.com/quotes might be something like: “Indicates a collection of quotes. To request a quote, POST a <request-for-quote> with a Content-Type header of application/vnd.restbucks+xml to the linked resource.”

That’s a perfectly respectable way of using links and link relations; in fact, it’s the strategy we employ in REST in Practice. But it can have its downsides. Most importantly, it can increase the coupling between the client and any resources that employ link relations.

Make no mistake: link relation semantics comprise out-of-band knowledge. There’s no magic here: link relations introduce a degree of coupling between a client and any server-governed resources that adopt them. The trick is to keep this coupling as low as possible. By putting control data in the link relation definition, we perhaps introduce more coupling than is strictly necessary.

Out-of-band data is less visible, and more difficult and more costly to change, than data that is inlined in the message. Whilst the control data may not change all that often, changes can and do sometimes happen; inlining the data allows these changes to be propagated to clients sooner rather than later. Control data produced at the time the response is generated is generally more recent than control data defined through some out-of-band mechanism.

Using lightly typed links helps separate semantics from control data. A “light” link relation indicates what the linked resource means in the context of the current representation – that’s all. This helps mitigate against a second, somewhat more subtle, downside of adding control data to link relations: the tendency to introduce action semantics. It’s no great step to shorten the link relation value above to http://relations.restbucks.com/quote, and to rewrite its semantic to read “Indicates an opportunity to request a quote by POSTing a <request-for-quote> with a Content-Type header of application/vnd.restbucks+xml to the linked resource.” At this point, our link has effectively become an operation. The typed-link-to-form strategy helps us concentrate on describing what a linked resource is, rather than what a link does. Link relations do not necessarily imply action semantics, but they can very easily be made to do so.

(Note: when adding links to representations, I still prefer to use a <link rel="..." href="..."> construct, or something similar, rather than <order-form href="...">. The reason for this is that elements such as <link> separate link syntax from semantic context, as explained here; and this is a good thing, because what a link ought look like – its syntax – changes far less than what a link might mean in a particular context. By separating these concerns, we make it easier to evolve a distributed application.)

Interestingly, on the wire, the result of submitting an XForm form looks exactly the same as if we’d simply POSTed a <request-for-quote> directly to /quotes:

//Request
POST /quotes HTTP/1.1
Host: restbucks.com
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<request-for-quote xmlns="http://schemas.restbucks.com/rfq">
  <items>
    <item>
      <description>Costa Rica Tarrazu</description>
      <amount>250g</amount>
    </item>
    <item>
      <description>Guatemala Elephant Beans</description>
      <amount>250g</amount>
    </item>
  </items>
</request-for-quote>

Knowing this, we could always add both a lightly typed link to a form and a heavily typed link to our shop representation:

<shop xmlns="http://schemas.restbucks.com/shop">
  <link rel="http://relations.restbucks.com/rfq"
        href="http://restbucks.com/request-for-quote"
        type="application/vnd.restbucks+xml"/>
  <link rel="http://relations.restbucks.com/quotes"
        href="http://restbucks.com/quotes"
        type="application/vnd.restbucks+xml"/>
</shop>

Two paths to the same result. I don’t recommend doing this: I include simply to highlight how a linked form achieves the exact same result, but with the added beenfit of having inlined control data.

Pre-filled forms/self-describing requests

Here’s another example of using a typed link to a form:

//Request
GET /quotes/1234
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Cache-Control: public
Date: Mon, 26 Jul 2010 10:01:00 GMT
Expires: Mon, 02 Aug 2010 10:01:00 GMT
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<quote xmlns="http://schemas.restbucks.com/quote">
  <items>
    <item>
      <description>Costa Rica Tarrazu</description>
      <amount>250g</amount>
      <price currency="GBP">4.40</price>
    </item>
    <item>
      <description>Guatemala Elephant Beans</description>
      <amount>250g</amount>
      <price currency="GBP">5.30</price>
    </item>
  </items>
  <link rel="http://relations.restbucks.com/order-form"
        href="http://restbucks.com/order-forms/1234"
        type="application/vnd.restbucks+xml"/>
</quote>

The link relation http://relations.restbucks.com/order-form indicates that the linked resource is something that allows an order to be submitted. Following this link, the client retrieves an order form:

//Request
GET /order-forms/1234
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Cache-Control: public
Date: Mon, 26 Jul 2010 10:01:05 GMT
Expires: Mon, 02 Aug 2010 10:01:00 GMT
Content-Type: application/vnd.restbucks+xml
Content-Length: ...
Content-Location: http://restbucks.com/quotes/1234

<model xmlns="http://www.w3.org/2002/xforms">
  <instance>
    <quote xmlns="http://schemas.restbucks.com/quote">
      <items>
        <item>
          <description>Costa Rica Tarrazu</description>
          <amount>250g</amount>
          <price currency="GBP">4.40</price>
        </item>
        <item>
          <description>Guatemala Elephant Beans</description>
          <amount>250g</amount>
          <price currency="GBP">5.30</price>
        </item>
      </items>
      <link rel="self"
            href="http://restbucks.com/quotes/1234"
            type="application/vnd.restbucks+xml"/>
    </quote>
  </instance>
  <submission
    resource="http://restbucks.com/orders" 
    method="post" 
    mediatype="application/vnd.restbucks+xml"/>
</model>

Once again, I’ve used an XForms form model, but this time I’ve pre-filled it with an <instance> element. Even so, there are no form fields to fill in; all the client needs to do is operate the form according to the inlined control data.

The interesting thing here is that /order-forms/1234 simply returns a different representation of the quote resource identified by /quotes/1234 (the response indicates as much in its Content-Location header). By supplying a forms-based representation of the quote, we inline all the information necessary to submit an order to an order processing engine. The client doesn’t need to compose an entity body; it simply needs to operate the form according to its control data. This results in a self-describing message being sent to /orders.

(In a real-world application I’d likely include a signature in the form body. This signature would guarantee that the client hasn’t tampered with the form contents prior to submitting the form to the order processing engine. The effectiveness of the signature depends on an out-of-band trust relationship having been established between the quoting engine and the order processing engine.)

The result of first following the link to the form, and then submitting the form, is to transition the overall state of the distributed application from Quote Requested to Order Placed, as illustrated in the following diagram:

Application state transition

Every request-response pair transforms application state. Retrieving the form enriches the client’s understanding of the current application state; that is, it opens up new opportunities for interacting with other resources. POSTing the form causes the application state to transition from Quote Requested to Order Placed.

The fact that the overall state of the application has changed is of no consequence to the server resources involved; the application state model is nowhere baked into the server resources. As far as the quote resource is concerned, it has simply been asked to surface a forms-based representation of itself. As far as the orders resource is concerned, it has simply created a new, subordinate order resource. This change in application state is, however, important to the client.

Summary

Understand the tradeoffs between inlining and putting control data in an out-of-band mechanism. Use the right controls for the job; understand the many different hypermedia capabilities at your disposal. The best resource for this is Mike Amundsen’s in-depth study of the hypermedia capabilities of many different kinds of hypermedia control. Recently, Andrew Wahbe started examining the need for machine-to-machine hypermedia, and the differences between controls for machines and controls for humans. Watch his blog for further discussion.

My understanding of hypermedia controls has been heavily influenced by my experience of the human web, where links and forms predominate. But when we talk about forms in a machine-to-machine context, it’s not the form field elements that are of interest, it’s the control data elements. These control data elements help program the client on the fly. The term “form” as it applies in a machine-to-machine context is likely an inappropriate metaphor; nonetheless, it does emphasize the fact that unsafe requests – and requests that have an entity body – require different hypermedia capabilities from simple GETs.

Because in the past I’ve tended to think form fields are redundant in machine-to-machine scenarios, I’ve avoided using forms at all, and have instead overloaded link relations with control data. But link relations are not a “get out of jail free” card. In overloading link relations, we add unnecessary coupling.

Coupling, of course, is not an all-or-nothing affair. There are degrees of coupling. We choose to accept some coupling because of the benefits it brings. But that doesn’t mean we should accept more coupling than is necessary; doing so can only inhibit our ability to evolve a distributed application.

7 Comments  |  Atom   RSS 2.0   Email

Responses

  1. Mike K says:

    September 2nd, 2010 at 4:36 pm (#)

    Hi Ian, I’ll just jump right in and try and get to the point!

    In-lining the control data propagates changes to clients, however those clients are mindless machines and aren’t capable of reacting as humans do .. they don’t have intuition.

    When the developer of a machine client writes its logic against that xform (out-of-band), it is coupled. There really is no magic here! ;)

    I agree completely that link relations introduce coupling – this happens in the human web; phishing attacks are a good example of how that type of coupling can be leveraged to do Bad Things – the difference being that our link relations are expressed with visual or textual symbols. More positive examples might be nav bars or bread crumbs.

    Because a machine processes forms according to out-of-band rules bestowed by its developer; I’m still unconvinced that putting control data in the link relation definition actually introduces any more coupling. Because of that, I believe that putting it there is in fact allowing clients and server to be more ‘honest’ with each other about what coupling is taking place. All ‘pain points’ between clients and server are neatly wrapped up into the link relations, providing clear single points of focus when considering how to evolve the system.

    Regardless; this is a really great article, and led me to think that a mechanism for versioning such ‘hard’ link relations in-band might be useful/necessary.

    Cheers,
    Mike

  2. iansrobinson says:

    September 2nd, 2010 at 4:59 pm (#)

    Awwwww, you peeked!

    Clients are mindless machines, but they can implement well-defined processing models. Something like XForms defines a processing model. Yes, we couple to the processing model; we don’t, however, couple directly to the many legitimate combinations of control data permitted within that processing model. It’s a level of indirection. As I say, coupling is not inherently undesirable, as long as we choose our coupling wisely.

    I think putting control data into a link relation can, on occasion (but not always – evaluate on a case-by-case basis), introduce more coupling than is necessary. We end up mixing concerns. If one concern is more volatile than the other, we risk having to evolve the whole thing despite only really wanting to change one part – and that can have a significant impact on existing parts of the system. If we put volatile control data in the link relation definition, we couple the evolution of the control data to the evolution of our link relation semantic.

    I’ve been down the route of thinking link relations solved a lot of problems; I now think that by overloading them with additional responsibilities we run the risk of introducing a different set of problems. The whole thing begins to smack of tunneling, which seems to be the (my) default alternative to thinking the issue through. Link relations, and other semantic annotations, can be a good thing; we haven’t, however, done a good job of understanding the limits of their applicability, or the trade-offs we make when we load them with multiple responsibilities. I do wonder whether versioning link relations may (may) end up treating the symptom rather than the underlying issue, but I’d be interested to hear more.

    Kind regards

    ian

  3. Scott Banwart's Blog » Blog Archive » Distributed Weekly 66 says:

    September 3rd, 2010 at 3:26 pm (#)

    [...] Using Typed Links to Forms [...]

  4. Jan Algermissen says:

    September 3rd, 2010 at 9:35 pm (#)

    Hi Ian,

    still need to digest the post, but there was already raging discussion on #rest IRC:
    http://rest.hackyhack.net/2010-09-03.html#251/h251

    Jan

  5. iansrobinson says:

    September 4th, 2010 at 3:45 pm (#)

    Hi Jan

    Thanks for the pointer. I do hope to pop in sometime, if only to toast a baguette with Mr. Kelly :)

    See you soon somewhere, I hope, online or in person,

    ian

  6. Andrew Wahbe says:

    September 5th, 2010 at 5:18 am (#)

    I like how you are basing this on xForms but as you acknowledge yourself — your taking the “Form” part out. I tend to think of a hypermedia client as a dynamic mediator between the “Control Interface” and the HTTP-based server interface. On the other side of the control interface is the portion of the client that is interacting with the user. By removing the form’s fields you’ve removed any trace of a control interface and are just left with the server’s interface — of course your client is bound to the server.

    Here’s a simple experiment to noodle on. Take all of your forms in the example and enhance them to explicitly query a client-side interface to extract the data and transform it into the format required by your service. It could be as simple as a few extra few tags representing a “call” to the client-side API with a reference to an XSLT transform that converts the XML result of the call to the media type required for submission. I’m not saying this is the best approach to take (likely a little bit too much code-on-demand) but it does make an interesting example of how the hypermedia engine can decouple the machine user (in this case the code that implements the client-side API) from the service.

    In fact, I’d take everything in your hypermedia format that is specific to buying coffee and consider it to be part of client-side API. The formats you are using for the request body should be part of that client API too. The rest of the format is mostly made up of generic mechanisms for interacting with the uniform interface. The machine user is an automated coffee ordering machine; the server could be anything. Of course it can still be a coffee purchasing service, but if you do things right, it might also be an application that surveys what the most popular types of coffee are.

    Andrew

  7. This Week in #REST – Volume 24 (Aug 23 2010 – Sep 5 2010) « This week in REST says:

    September 6th, 2010 at 8:27 am (#)

    [...] Using Typed Links to Forms – “Understand the tradeoffs between inlining and putting control data in an out-of-band mechanism. Use the right controls for the job; understand the many different hypermedia capabilities at your disposal.” (by Ian Robinson) [...]