Ruby On REST 5: Learn Hypermedia By Making Fruit Salad

{{{

Let me start this post by quoting something smart.

“REST [is an] architectural style for distributed hypermedia systems”

That actually is the “first line, chapter 5”:http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm of Roy Fielding’s thesis about REST. I gave a couple of talks last year about hypermedia and the misunderstandings in REST in the Rails world and this post tries to sum up with that by focusing on the _hypermedia_ aspect of this architectural concept.

h3. Challenge: Make Fruit Salad!

In the “last posts”:http://nicksda.apotomo.de/tag/rest/ we discussed using the “Roar gem”:http://github.com/apotonick/roar for designing and implementing REST systems in Ruby. We were using fruits and bowls as an exemplary domain – let’s keep up with that and fix a fruit salad today.

As a first step it makes sense getting a bowl for all the ingredients. In our REST system, we just POST to the bowls URL.

POST http://bowls
Content-type: application/json
------------------------------
{"location": "desk"}

The request body contains a minimal document specifying the location for the created bowl. Here’s what we get back.

{"location":"desk",
 "fruits":[],
 "links":[
  {"rel":"self",  "href":"http://bowls/desk"},
  {"rel":"fruits","href":"http://bowls/desk/fruits"}
]}

By reading this I figure out that the bowl on my desk was created, but doesn’t contain any fruits, yet. Also, these _”links”_ seem understandable, while @self@ might point to the bowl resource itself the @fruits@ link probably directs to a collection resource listing all the ingredients in that very bowl.

Looks as if a URL gets a “meaning” by specifying a @rel@ attribute with it.

I infered all that by intuition, as JSON is a pretty simple representation format. And this is the first problem when trying to understand hypermedia. JSON as it doesn’t include any semantics, the links are, well, useless as they’re not understandable to machines. What we need is a *hyper-media type*. Get it on!

h3. What Is A Media Type, Sir?

A concept called _media type_ gives both syntax and semantics to a document. It is important to understand that a simple media type like JSON doesn’t define anything. It just provides a medium (or format) to encode information.

Why not put it that way: JSON and XML are like primitive communication mechanics. Where XML uses smoke signals for exchanging messages, JSON is human voice. A poor example.

However, listening to my voice doesn’t mean you _understand_ what I’m saying. Reading JSON is like listening to my _sounds_, but the noize might not make sense to you. Ok?

The media type is like a language. You understanding the media type “english” and me speaking (JSON) in english (media type) makes us happy chatters. And suddenly, a series of sounds turn into “Would you like another beer?”. You _understand_ me since you know the syntax and the semantics of my sounds. That is a media type!

h3. Now That We Understand Hypermedia, What To Do With It?

Instead of using plain, dumb JSON I’d like to introduce a real hypermedia format called “HAL”:http://stateless.co/hal_specification.html which is “specifically for exposing RESTful hypermedia APIs”.

POST http://bowls
Content-type: application/hal+json
------------------------------
{"location": "desk"}

Note that we used the @application/hal+json@ content type desparately hoping the web service understands this media format. Check the response.

{"location":"desk",
 "_embedded":{"fruits":[]},
 "_links":{
  "self":  {"href":"http://bowls/desk"},
  "fruits":{"href":"http://bowls/desk/fruits"}
}}

It obviously does, and now the links are encoded a little bit different, following the HAL standard. While this doesn’t make a real difference for you human being, it changes a lot in machine context. By using this media format, we added semantics: Now, the HAL-aware client _knows_ that links can be found at the @_links@ key, that they’re keyed by @rel@ and so on.

Think about it briefly. Growing up with human voice you understood JSON before. However, now that you learned HAL, you understand all the bits and pieces in the document just by applying the specification rules.

h3. I’m Still Hungry!

Sorry for that detailed discussion about hypermedia types, I’m really getting hungry as well, so let’s add some fruits to the bowl.

POST http://bowls/desk/fruits
Content-type: application/hal+json
------------------------------
{"title": "Apple"}

An apple a day keeps the doctor away. Assuming it is sufficient to post this mini JSON document to the @fruits@ URL I add an apple to my salad. Did that work?

GET http://bowls/desk
Content-type: application/hal+json
------------------------------
{"location":"desk",
 "_embedded":{
  "fruits":[
   {"title":"Apple",
    "colors":[],
    "_links":{"self":{"href":"http://fruits/apple"}}
  }]  
 "_links":{
  "self":  {"href":"http://bowls/desk"},
  "fruits":{"href":"http://bowls/desk/fruits"}}
}

Yeah! I can see an apple inside the @_embedded@ key, which is HAL’s way to nest resources in representations. Also, the apple contains a link again pointing to its resource.

It is needless to note that I could go on like this and POST more fruits to the @fruits@ collection resource in order to enrich my delicious salad.

h3. What Did I Just Do?

This brief example was brief. Nevertheless, it demonstrated the use of hypermedia. Here’s what I did.

  1. First, I POSTed to @http://bowls@ to create a bowl.
  2. The returned document points me to its @fruits@ resource.
  3. To add fruits, I POST to @http://bowls/desk/fruits@ as defined in the representation.
  4. I retrieve the updated bowl by following the @self@ URL of the bowl.

Well, what’s so special about that?

The key is, I didn’t compute any URL except the initial URL in (1.) – this is what we call the *single entry point*. No knowledge about follow-up URLs was needed to operate my fruit salad API. Everything I need to know is included in the representations.

Actions (aka URLs) that are meaningful in the current application state can be found in the document without any need to build URLs myself. This concept is called *HATEOAS* – a beautiful name… for a cat.

h3. Thou Shall Not Make Any Fruit Salad Without Hypermedia!

Roy Fielding, the inventor of REST, states that “your API is RESTFUL if and only if it is hypermedia-driven”:http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven! In my words, that’ll mean no URL code should be hard-wired into your REST client – except for the single entry point URL. Any additional resource must be extracted from returned documents. And, hey, this is the very reason why REST is defined as a style for “distributed _hypermedia_ systems”.

How that works with “the Roar gem”:http://github.com/apotonick/roar is subject to discussion in my upcoming next post! Stay tuned and enjoy life!
}}}

Advertisement

8 thoughts on “Ruby On REST 5: Learn Hypermedia By Making Fruit Salad

  1. Thanks for posting this. I’ve always wished that Rails started with this concept when it went down the “RESTful” route but its good to see that hyper media is making its way into more discussions.

    Like

  2. @Adam: Adam! Missed your comments during the last months, good to see you’re back ๐Ÿ˜‰ There’s still lots of space in Rails and luckily this concept can be used in your app out-of-the-box without having to modify Rails. Let’s see how it evolves…

    Like

  3. I’m glad to see continuing discussion related to REST (or Hypermedia) API’s. I’ve been working on a little gem at work that is trying to build a HAL+JSON response when a client makes a request using application/hal+json.

    Right now it’ll build up the appropriate links to self and parent (if its an embedded object). It’ll also add links to models that you have associations with. I hope to keep working on it and eventually publish it.

    I’m interested in Roar, especially with your next post(s).

    Like

  4. Single point entry design makes sense, to decouple the client from the resource server so that any changes to the way the resources are stored or represented do not affect the client, as long as the single URL does not change. And it seems logical that once a resource is returned, everything important to that resource should be discoverable in its representation. Nice.

    Like

  5. So to access some resources i have to make few GET requests only to get proper URL for this action?

    How this is different from for example full resources and actions map under root url of API? Something like WADL in JSON?

    I don’t see any reason to embed links in EVERY fetched resource if I need them only once. If you want to change resource link, you should version your API.

    Like

  6. @Adam: In a better setup you probably wouldn’t have to do multiple GET requests and design your representation links smarter – it’s up to you where you put which link. I just tried to show the general concept of hypermedia here.

    > Something like WADL in JSON?
    Whereas WADL is a language to describe actions only, hypermedia tries to integrate that into your actual business representations.

    > you should version your API.
    Hypermedia is an approach to make versioning unnecessary since clients can (theoretically, I know) auto-discover links/actions so you don’t have to rewrite your clients after you change URLs in the service. Right, Steve?

    Like

  7. Why are you referencing to a fruit resource in _links when its already in _embedded ? and is it a bad habbit to have a nested resource uri like
    “_links”:{“self”:{“href”:”http://bowls/desk/fruits/apple”}}

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s