<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Steve Klabnik — REST &amp; Hypermedia</title><description>REST, hypermedia APIs, HTTP, and web architecture.</description><link>https://steveklabnik.com/</link><item><title>Hypermedia FizzBuzz</title><link>https://steveklabnik.com/writing/hypermedia-fizzbuzz/</link><guid isPermaLink="true">https://steveklabnik.com/writing/hypermedia-fizzbuzz/</guid><description>I read a really great blog post last week: Solving FizzBuzz with Hypermedia . In it, Stephen Mizell builds a FizzBuzz service using Siren , and then shows how client code evolves. I wanted to explain exactly why I think this example is amazing, because I’m not sure it’s exactly…</description><pubDate>Fri, 02 May 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I read a really great blog post last week: &lt;a href=&quot;http://smizell.com/weblog/2014/solving-fizzbuzz-with-hypermedia&quot;&gt;Solving FizzBuzz with Hypermedia&lt;/a&gt;. In it, Stephen Mizell builds a FizzBuzz service using &lt;a href=&quot;https://github.com/kevinswiber/siren&quot;&gt;Siren&lt;/a&gt;, and then shows how client code evolves. I wanted to explain exactly why I think this example is amazing, because I’m not sure it’s exactly obvious.&lt;/p&gt;
&lt;h2 id=&quot;fizzbuzz-really&quot;&gt;FizzBuzz? Really?&lt;/h2&gt;
&lt;p&gt;The first thing that makes this post brilliant is that it uses FizzBuzz. While FizzBuzz has historically been a simple interview question to make sure that you can actually write some basic code, in this case, it works well because it’s a very, very simple programming problem. When writing examples, there’s always tension between real-world and straw-man examples. If you make it too real-world, all sorts of incidental details creep in and distract from your main point. If you make a trivial example, it can be claimed that it works for your simple example, but not for ‘real’ examples. Now, this may be true of FizzBuzz, but what I like about it is that it’s an example that everyone is already familiar with. It has &lt;em&gt;just enough&lt;/em&gt; actual computing that it straddles that line.&lt;/p&gt;
&lt;h2 id=&quot;haters-gonna-hateoas&quot;&gt;Haters gonna HATEOAS&lt;/h2&gt;
&lt;p&gt;The real insight of this post, however, is demonstrating one of the hardest concepts to grok about the hypermedia approach: the way in which hypermedia reduces duplication, by moving application entirely to the server. This is the core of that dreaded “HATEOAS” concept, and it’s where people get tripped up. Here’s the sample client in the hypermedia style:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;from siren import SirenResource as Hyperclient&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BASE_URL = &quot;http://fizzbuzzaas.herokuapp.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def fizzbuzz(resource):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Prints the fizzbuzz value and follows &quot;next&quot; links&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    print resource.properties[&quot;value&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if resource.has_link(&quot;next&quot;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fizzbuzz(resource.follow_link(&quot;next&quot;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def begin_fizzbuzz(resource):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Follows the first link, then hands off to fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if resource.has_link(&quot;first&quot;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fizzbuzz(resource.follow_link(&quot;first&quot;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;root_resource = Hyperclient(BASE_URL, path=&quot;/&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;begin_fizzbuzz(root_resource)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s talk about what this client’s goal is: to print a list of numbers. This is a classic recursive list traversal algorithm: we start at the head of the list (&lt;code&gt;first&lt;/code&gt;), and then follow the links until we get to the end. (&lt;code&gt;next&lt;/code&gt;) This client &lt;em&gt;does not actually calculate fizzbuzz&lt;/em&gt;. It just so happens that the service we’re pointing it at calculates FizzBuzz. If we pointed it at, say, a list of search results, where the same link relations and Siren were used, it would still work!&lt;/p&gt;
&lt;p&gt;Compare this to the non-hypermedia client:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BASE_URL = &quot;http://fizzbuzzaas.herokuapp.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def fizzbuzz(params):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    url = BASE_URL + &quot;/fizzbuzz&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    response = requests.get(url, params=params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    response_json = response.json()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    return response_json[&quot;properties&quot;][&quot;value&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;for number in range(1, 101):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    print fizzbuzz({&quot;number&quot;: number })&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This client doesn’t fully calculate FizzBuzz on its own, but it does have some of the logic for doing so embedded inside. We explicitly loop over the range FizzBuzz needs, and we print out each value.&lt;/p&gt;
&lt;p&gt;Why does this matter? It seems like a pretty subtle distinction. Well, this logic already exists on the server. We’re duplicating that logic here. This duplication creates coupling across the client/server boundary. For example, if we pointed this client at a “search results” resource, we would get 100 search results, even if there are less. We’re not letting the server guide our interactions, and we’re coding business logic into the client.&lt;/p&gt;
&lt;p&gt;This comes back to bite us when we try to change the client. As Stephen’s next example shows:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;import requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BASE_URL = &quot;http://fizzbuzzaas.herokuapp.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;STARTS_AT = 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ENDS_AT = 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ADD = 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def fizzbuzz(params):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    url = BASE_URL + &quot;/fizzbuzz&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    response = requests.get(url, params=params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    response_json = response.json()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    print response_json[&quot;properties&quot;][&quot;value&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    params[&quot;number&quot;] += ADD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if params[&quot;number&quot;] &amp;#x3C;= ENDS_AT:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fizzbuzz(params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fizzbuzz({ &quot;number&quot;: STARTS_AT })&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This version uses different start, end, and skip parameters. And so we had to throw out our entire old client, because it was too tightly coupled to the notion of how to calculate FizzBuzz. We’re now manually doing the skip and end calculations, even further coupling this client. Our fundamental algorithm even changed: the last client was iterative, but this client is recursive. We could have still made it iterative, but that still would have been a lot of change.&lt;/p&gt;
&lt;p&gt;Now , the hypermedia version:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;from siren import SirenResource as Hyperclient&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BASE_URL = &quot;http://fizzbuzzaas.herokuapp.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def fizzbuzz(resource):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Prints the fizzbuzz value and follows &quot;next&quot; links&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    print resource.properties[&quot;value&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if resource.has_link(&quot;next&quot;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fizzbuzz(resource.follow_link(&quot;next&quot;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def begin_fizzbuzz(resource):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Follows the first link, then hands off to fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if resource.has_link(&quot;first&quot;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        fizzbuzz(resource.follow_link(&quot;first&quot;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;def custom_fizzbuzz(root_resource, params):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Submits actions for custom fizzbuzz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    resource = root_resource.take_action(&quot;custom-fizzbuzz&quot;, params)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    begin_fizzbuzz(resource)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;root_resource = Hyperclient(BASE_URL, path=&quot;/&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;params = { &quot;startsAt&quot;: 4, &quot;endsAt&quot;: 20, &quot;add&quot;: 2 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;custom_fizzbuzz(root_resource, params)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Very little has changed between the last client and this one. We just added an extra method to submit our custom start point, but the rest of the code is all identical: we’re still traversing the list, with the same code. This worked because we chose the right behavior for our client, and let the server handle all of the business logic.&lt;/p&gt;
&lt;h2 id=&quot;traversal-from-the-root&quot;&gt;Traversal from the root&lt;/h2&gt;
&lt;p&gt;The last thing this post does is demonstrate how an actual hypermedia API starts from the API root and progresses from there. Lots of people hear this, and assume that there will be way more API calls than in an API in a different style. That’s because they assume that the client will be written in the same way as they’re used to: function calls over HTTP. As you can see here, we don’t start each call from the root of the API, we start &lt;em&gt;our initial interaction with the service&lt;/em&gt; from the root of the API. Each step is just one more call after that, just like in any other API.&lt;/p&gt;
&lt;p&gt;This is the other part of the hypermedia constraint that trips people up. Navigating a state machine of your API’s business process has a very different feel than making function calls over HTTP. It requires a different kind of mindset and approach to building clients. This is the area of hypermedia research that’s been least published about. The server-side story has been fleshed out, but the real frontier in hypermedia theory and practice is client building guidelines, and that’s why I like this example so much.&lt;/p&gt;</content:encoded></item><item><title>The profile link relation and you</title><link>https://steveklabnik.com/writing/the-profile-link-relation-and-you/</link><guid isPermaLink="true">https://steveklabnik.com/writing/the-profile-link-relation-and-you/</guid><description>I was quite pleased when RFC 6906 was finalized. It’s a really useful pattern that people are using to enhance documentation of their APIs. Let’s start with an example. I tweet something like this: “Oh man, the example.com API is super awesome. You should check it out!” -…</description><pubDate>Mon, 06 May 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was quite pleased when &lt;a href=&quot;http://tools.ietf.org/html/rfc6906&quot;&gt;RFC 6906&lt;/a&gt; was finalized. It’s a really useful pattern that people are using to enhance documentation of their APIs.&lt;/p&gt;
&lt;p&gt;Let’s start with an example. I tweet something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Oh man, the example.com API is super awesome. You should check it out!” - &lt;a href=&quot;https://twitter.com/steveklabnik&quot;&gt;@steveklabnik&lt;/a&gt; seconds ago from web&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You don’t know anything about this API or what it offers. So you fire up &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -i http://example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Length: 273&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;wtl&quot;: &quot;MjAxMy0wNS0wNiAxMjo1Nzo1MyAtMDcwMA==\n&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;grobb34s&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;flog&quot;: &quot;Top 100 foobars&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;zilch&quot;: &quot;http://example.com/foo/bar?baz=qux&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;flog&quot;: &quot;Mega Troll Title&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;zilch&quot;: &quot;http://example.com/exploit.exe/foobar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be blunt, this makes absolutely no sense. You tell me so, and the next day, I tell you to check it out again. You grumble, and get back to the &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -i http://example.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Length: 273&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt; Link: &amp;#x3C;http://example.com/profile&gt;; rel=&quot;profile&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;wtl&quot;: &quot;MjAxMy0wNS0wNiAxMjo1Nzo1MyAtMDcwMA==\n&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &quot;grobb34s&quot;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;flog&quot;: &quot;Top 100 foobars&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;zilch&quot;: &quot;http://example.com/foo/bar?baz=qux&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;flog&quot;: &quot;Mega Troll Title&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &quot;zilch&quot;: &quot;http://example.com/exploit.exe/foobar&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh, wait. “Profile”. Let’s see what that’s about:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -i http://example.com/profile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: text/plain&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Length: 548&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The Example.com API&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;===================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Example.com provides access to our blog through an API.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;In the API, you&apos;ll see two major things of interest: `wtl` and `grobb34s`.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;## wtl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The value provided under the `wtl` key is the time the latest blog post&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;was posted, in &quot;%Y-%m-%d %H:%M:%S %z&quot; format. This value is then Base64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;encoded.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;## grobb34s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The `grobb34s` key will hold an array of blog posts. These posts are&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;represented by a JSON object with two keys. `flog` has the title, suitable for&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;display, and `zilch` contains a link to the post.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh. You don’t care about some blog with such terrible titles, so you go about your day.&lt;/p&gt;
&lt;h2 id=&quot;self-descriptive-ness&quot;&gt;self-descriptive-ness&lt;/h2&gt;
&lt;p&gt;You may consider this a highly contrived example, but it’s not as contrived as you think. In Fielding’s thesis, he describes a ‘self-described messages’ constraint, which means that any API call should be able to be understood alone, without additional context.&lt;/p&gt;
&lt;p&gt;In HTTP, this information is generally provided via the &lt;code&gt;Content-Type&lt;/code&gt; header. It describes a media type (such as &lt;code&gt;application/json&lt;/code&gt; in this example) that describes the rules for processing the response. When writing a HTTP client, you fetch the response, check the &lt;code&gt;Content-Type&lt;/code&gt;, and then invoke the correct parser based on the type provided.&lt;/p&gt;
&lt;p&gt;But many times are very general. Take &lt;code&gt;application/json&lt;/code&gt;, for example. It says nothing about blog posts. A user-agent that only knows about &lt;code&gt;application/json&lt;/code&gt; is very much like you as a human seeing gibberish keys and values; it’s not smart enough to make assumptions based on the text of keys and values it may see in JSON. However, with the added context of a profile, we have enough information to make sense of this strange API. And any user-agent that sees a profile that it recognizes can act on those new semantics, too.&lt;/p&gt;
&lt;h2 id=&quot;json-api&quot;&gt;JSON API&lt;/h2&gt;
&lt;p&gt;This is one of the reasons that we’re working on &lt;a href=&quot;http://jsonapi.org/&quot;&gt;JSON API&lt;/a&gt;, a standard media type for APIs that use JSON. Generic JSON has no standard semantics that are useful to API authors, since it’s a very generic format. By declaring a new media type with common features to many APIs, we can write generic tools that handle the 80% of cases that come up during API development.&lt;/p&gt;
&lt;p&gt;And if the generic case doesn’t suit your requirements, you can always extend it with profiles. In fact, it’d be nice if many people just added a &lt;code&gt;Link&lt;/code&gt; header to their existing API documentation; that’d start alleviating this problem.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you enjoyed this article, you might want to check out my in-progress book on building APIs that respect standards and HTTP, &lt;a href=&quot;http://www.designinghypermediaapis.com/&quot;&gt;Designing Hypermedia APIs&lt;/a&gt;. This post also serves as &lt;a href=&quot;http://www.designinghypermediaapis.com/blog/the-profile-link-relation-and-you.html&quot;&gt;its first blog post&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>The next iteration of &quot;Designing Hypermedia APIs&quot;</title><link>https://steveklabnik.com/writing/the-next-iteration-of-designing-hypermedia-apis/</link><guid isPermaLink="true">https://steveklabnik.com/writing/the-next-iteration-of-designing-hypermedia-apis/</guid><description>I sent out an email today to everyone who’d previously purchased Designing Hypermedia APIs . Here’s the text: Hey there, First of all, I want to apologize for sending you an email. I try to keep these to a minimum. But this one is important. I haven&apos;t been uploading new content…</description><pubDate>Tue, 12 Feb 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I sent out an email today to everyone who’d previously purchased &lt;a href=&quot;http://www.designinghypermediaapis.com/&quot;&gt;Designing Hypermedia APIs&lt;/a&gt;. Here’s the text:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Hey there,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;First of all, I want to apologize for sending you an email. I try to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;keep these to a minimum. But this one is important.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I haven&apos;t been uploading new content lately for a few reasons.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Holidays are complicated, I wasn&apos;t feeling inspired... but this is the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;real reason: I&apos;ve totally moved the site to something different. I&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;just updated it, so the DNS might need an update, but&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;http://www.designinghypermediaapis.com/ is all-new. Here&apos;s the deal:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1. Gone is logging in and reading it online. PDF/ePUB/MOBI now.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2. Because you purchased a copy before, you get the big bundle. Thank&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;you for your support over the last year.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3. You&apos;ll be getting another email with a link to download the files.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;When I send an update, you&apos;ll get a new email with a new link.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4. The current written content is basically an appendix: I&apos;m going to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;be writing a more traditional book, from start to finish. It&apos;ll walk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;you through building an application, both client and server.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;5. I want this to be of the highest quality, so I&apos;m not going to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;commit to a schedule.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;If you aren&apos;t a part of the mailing list, we&apos;re doing a reading club&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;over the next few months, &quot;Building Hypermedia APIs with HTML5 and&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Node.&quot; You can join by emailing hypermedia@librelist.com.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thank you once again for your support of this project, I really&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;appreciate it. As always, any and all feedback welcome: I bet I can do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;some nicer formatting of the PDF/ePUB/MOBI now that I have them&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;generating.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wooo!&lt;/p&gt;</content:encoded></item><item><title>I invented hypermedia APIs by accident</title><link>https://steveklabnik.com/writing/i-invented-hypermedia-apis-by-accident/</link><guid isPermaLink="true">https://steveklabnik.com/writing/i-invented-hypermedia-apis-by-accident/</guid><description>Long long ago, I got an internship in college. Back then, I didn’t know anything about web development. My college professor said “GET and POST are the same thing, it’s just that GET requests show parameters in the URL bar.” But a friend of mine was working at this…</description><pubDate>Fri, 21 Dec 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Long long ago, I got an internship in college. Back then, I didn’t know anything about web development. My college professor said “GET and POST are the same thing, it’s just that GET requests show parameters in the URL bar.” But a friend of mine was working at this post-acquisition startup. They still operated as an autonomous unit within the parent company, so they were still pretty fun to work for. People would upload us MP3s and we’d give them a podcast. They’d get a blog, the necessary RSS, we’d help get them listed in iTunes, all that jazz.&lt;/p&gt;
&lt;p&gt;Then the iPhone came out, and you could make apps for it.&lt;/p&gt;
&lt;p&gt;Bizdev decided that we should sell apps to our clients, who could then sell them to their audience and help finance the show. We’d do all the dev work, we’d all make money, it’d be a good time. So they asked me to write an iPhone app generator. We picked a big feature set, and people could give us some images, pick their individual features, and set some other config options. We’d take that file, and compile in them as defaults. All seemed good.&lt;/p&gt;
&lt;p&gt;Then the first app got rejected: it turns out that Apple has some restrictions on the bitrate of MP3s that you could download. I suspected that AT&amp;#x26;T wasn’t very happy with you using lots of data back then. Anyway, we had to get around this issue: we wanted to serve up quality audio. What to do?&lt;/p&gt;
&lt;p&gt;I don’t remember who came up with it, but we decided that the first thing the app would do would be to fetch the config file from the server, to see if any of the defaults were changed. It was just XML, so the iPhone could parse it easily, and then change whatever was different. So we’d have something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&amp;#x3C;config&gt;  &amp;#x3C;link href=&quot;http://example.com/low.rss&quot; rel=&quot;podcast_url&quot; /&gt;&amp;#x3C;/config&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don’t remember the exact schema, but you get the idea.&lt;/p&gt;
&lt;p&gt;Anyway, so we’d link to the low quality feed while the app was in review, and then later, we’d change the response to this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&amp;#x3C;config&gt;  &amp;#x3C;link href=&quot;http://example.com/high.rss&quot; rel=&quot;podcast_url&quot; /&gt;&amp;#x3C;/config&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the client would fetch the high quality feed. No client code needed to change! We’d managed to sneak around a restriction in the review process.&lt;/p&gt;
&lt;p&gt;But why stop here? Once we saw this flexibility, we started taking full advantage. People could set up a bunch of different configuration options, and that would change the UI based on their choices. So, for example, they could choose to be contacted by email, they could put in a website or two, and the page would change. Here’s a mockup of the web page:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://svbtleusercontent.com/inline_steveklabnik_24409213486218_raw.png&quot; alt=&quot;https://svbtleusercontent.com/inline_steveklabnik_24409213486218_raw.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;This would cause our app to serve up the following XML:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&amp;#x3C;config&gt;  &amp;#x3C;link href=&quot;http://example.com/high.rss&quot; rel=&quot;podcast_url&quot; /&gt;  &amp;#x3C;about&gt;    &amp;#x3C;links&gt;      &amp;#x3C;link href=&quot;http://example.com&quot;&gt;Homepage&amp;#x3C;/link&gt;      &amp;#x3C;link href=&quot;http://example.com/about&quot;&gt;About Us&amp;#x3C;/link&gt;    &amp;#x3C;/links&gt;    &amp;#x3C;phone&gt;5558675309&amp;#x3C;/phone&gt;    &amp;#x3C;email&gt;foo@example.com&amp;#x3C;/email&gt;  &amp;#x3C;/about&gt;&amp;#x3C;/config&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that would make this appear in the “about” section of the app:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://svbtleusercontent.com/inline_steveklabnik_24409223801964_raw.png&quot; alt=&quot;https://svbtleusercontent.com/inline_steveklabnik_24409223801964_raw.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;Neat, eh? We’d turn the email into a &lt;code&gt;mailto:&lt;/code&gt; link and the phone into a &lt;code&gt;tel:&lt;/code&gt; one, as well.&lt;/p&gt;
&lt;p&gt;Anyway, maybe later they’d go back and unset their phone number, and the about us link. So then we’d generate this XML:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&amp;#x3C;config&gt;  &amp;#x3C;link href=&quot;http://example.com/high.rss&quot; rel=&quot;podcast_url&quot; /&gt;  &amp;#x3C;about&gt;    &amp;#x3C;links&gt;      &amp;#x3C;link href=&quot;http://example.com&quot;&gt;Homepage&amp;#x3C;/link&gt;    &amp;#x3C;/links&gt;    &amp;#x3C;email&gt;foo@example.com&amp;#x3C;/email&gt;  &amp;#x3C;/about&gt;&amp;#x3C;/config&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But check out what the app would do:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://svbtleusercontent.com/inline_steveklabnik_24409247735934_raw.png&quot; alt=&quot;https://svbtleusercontent.com/inline_steveklabnik_24409247735934_raw.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;Whoah! Isn’t that rad? The UI would change based on the config.&lt;/p&gt;
&lt;p&gt;Here’s what’s even rad-er: because the app would read the config on each load, changes would get propagated very quickly. If you took your email away, everyone’s apps would no longer have it, as if by magic. Next time they loaded up the app, it just wouldn’t be there any more.&lt;/p&gt;
&lt;p&gt;Here’s what’s &lt;strong&gt;even rad-er&lt;/strong&gt;: You wouldn’t need to go through the App Store approval process to push this change out to the users. It Just Worked. If you’re an app developer, and you’ve been forced to sit through long waits to push out a release, you know how painful it can be. I don’t know how fast it is these days, but back then, it could take a month. With this approach, we could, say, remove a feature, and it’d be gone immediately. No oversight. If we added a new feature, older apps would still work, because they’d just ignore the new part of the config, and people who got the new version would get the newest features.&lt;/p&gt;
&lt;p&gt;Years later, after doing tons of research on Hypermedia APIs, I realized that that thing I did long ago was a form of it, and it provided us with a pretty massive benefit. So of course I wasn’t the first one to come up with it; my point is that I implemented a system in line with hypermedia principles because it made sense to do so, even though I had no idea that Roy Fielding was a PhD candidate. And I certainly had no way of articulating it as a ‘style,’ it was just a neat hack.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you liked this story, you may care to learn about what else I’ve learned along the way with Hypermedia APIs. I wrote an e-‘book’ about it called &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;Designing Hypermedia APIs&lt;/a&gt;. It’s only $20, and you get updates forever! I’m actively working on adding new content, and I’ll be doing a total redux in the new year.&lt;/p&gt;</content:encoded></item><item><title>Hypermedia API reading list</title><link>https://steveklabnik.com/writing/hypermedia-api-reading-list/</link><guid isPermaLink="true">https://steveklabnik.com/writing/hypermedia-api-reading-list/</guid><description>Originally, this post was titled “A RESTful Reading List,” but please note that REST is over. Hypermedia API is the new nomenclature. I’ve been doing an intense amount of research on Hypermedia APIs over the last few months, and while I didn’t save every resource I found, I’ve…</description><pubDate>Mon, 27 Feb 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Originally, this post was titled “A RESTful Reading List,” but please note that &lt;a href=&quot;/posts/2012-02-23-rest-is-over&quot;&gt;REST is over. Hypermedia API is the new nomenclature.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’ve been doing an intense amount of research on Hypermedia APIs over the last few months, and while I didn’t save every resource I found, I’ve made a list here of the most important.&lt;/p&gt;
&lt;p&gt;I’ll be updating this post as I get new resources, so check back!&lt;/p&gt;
&lt;h2 id=&quot;the-book-list&quot;&gt;The book list&lt;/h2&gt;
&lt;p&gt;If you want to go from ‘nothing to everything,’ you can do it by reading just a few books, actually. I’m going to make all of these links affiliate. I purchase a &lt;em&gt;lot&lt;/em&gt; of books myself, maybe suggesting things to you can help defray the cost of my massive backlog. All are easily searchable on Amazon if you’re not comfortable with that.&lt;/p&gt;
&lt;p&gt;Start off with &lt;a href=&quot;http://www.amazon.com/gp/product/0596529260/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=0596529260&quot;&gt;Restful Web Services&lt;/a&gt; by Leonard Richardson and Sam Ruby. This book is fantastic from getting you from zero knowledge to “I know how Rails does REST by default,” which is how most people do REST. But as you know, that’s flawed. However, understanding this stuff is crucial, not only for when you interact with REST services, but also for understanding how Hypermedia APIs work differently. This baseline of knowledge is really important.It also comes in &lt;a href=&quot;http://www.amazon.com/gp/product/0596801688/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=0596801688&quot;&gt;cookbook form&lt;/a&gt;. You really only need one or the other; pick whichever format you like.&lt;/p&gt;
&lt;p&gt;Next up, read &lt;a href=&quot;http://www.amazon.com/gp/product/0596805829/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=0596805829&quot;&gt;REST in Practice: Hypermedia and Systems Architecture&lt;/a&gt;. This book serves as a great &lt;em&gt;bridge&lt;/em&gt; to understanding Hypermedia APIs from the RESTful world. Chapters one through four read like Richardson &amp;#x26; Ruby; yet they start slipping in the better hypermedia terminology. Chapter five really starts to dig into how Hypermedia APIs work, and is a great introduction. Chapter six covers scaling, chapter seven is an introduction to using ATOM for more than an RSS replacement, nine is about security, and eleven is a great comparison of how Hypermedia and WS-* APIs differ. All in all, a great intermediate book.&lt;/p&gt;
&lt;p&gt;To really start to truly think in Hypermedia, though, you &lt;em&gt;must&lt;/em&gt; read &lt;a href=&quot;http://www.amazon.com/gp/product/1449306578/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=1449306578&quot;&gt;Building Hypermedia APIs with HTML5 and Node&lt;/a&gt;. Don’t let the title fool you, as Mike says in the introduction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[HTML5, Node.js, and CouchDB] are used as tools illustrating points about hypermedia design and implementation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not a Node.js book. I find Node slightly distasteful, but all the examples were easy to follow, even without more than a cursory working knowledge.&lt;/p&gt;
&lt;p&gt;Anyway, the book: Mike says something else that’s really important in the intro:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While the subject of the REST architectural style comes up occasionally, this book does not explore the topic at all. It is true that REST identifies hypermedia as an important aspect of the style, but this is not the case for the inverse. Increasing attention to hypermedia designs can improve the quality and functionality of many styles of distributed network architecture including REST.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And, in the afterward:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;However, the aim of this book was not to create a definitive work on designing hypermedia APIs. Instead, it was to identify helpful concepts, suggest useful methodologies, and provide pertinent examples that encourage architects, designers, and developers to see the value and utility of hypermedia in their own implementations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think these two statements, taken together, describe the book perfectly. The title is “Building Hypermedia APIs,” not “Designing.” So why recommend it on an API design list? Because understanding media types, and specifically hypermedia-enabled media types, is the key to understanding Hypermedia APIs. Hence the name.&lt;/p&gt;
&lt;p&gt;Mike is a great guy who’s personally helped me learn much of the things that I know about REST, and I’m very thankful to him for that. I can’t recommend this book highly enough.&lt;/p&gt;
&lt;p&gt;However, that may leave you wondering: Where’s the definitive work on how to actually build and design a Hypermedia API? Did I mention, totally unrelated of course, that &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;I’m writing a book&lt;/a&gt;? ;)&lt;/p&gt;
&lt;p&gt;Yes, it still has REST in the title. Think about that for a while, I’m sure you can see towards my plans. I’m planning on a beta release as soon as I’m recovered from some surgery this week, but I’m not sure how long that will take, exactly. So keep your eyes peeled.&lt;/p&gt;
&lt;h3 id=&quot;books-i-dont-recommend&quot;&gt;Books I don’t recommend&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/1449310508/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=1449310508&quot;&gt;REST API Design Rulebook&lt;/a&gt;, while I haven’t actually read it, seems quite terrible. Let me copy an &lt;a href=&quot;http://www.amazon.com/review/R2F4STDF7XS7U3/ref=cm_cr_dp_perm?ie=UTF8&amp;#x26;ASIN=1449310508&amp;#x26;nodeID=283155&amp;#x26;tag=&amp;#x26;linkCode=&quot;&gt;Amazon review&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The first chapters give a good feel for the vocabulary, and some good techniques for implementing REST. A lot of the ‘rules’, especially those related to basic CRUD operations, are clean and simple with useful examples.Unfortunately, the later chapters get more and more focused on specifying something called ‘WRML’, which is a concept/language newly introduced in this book as far as I can tell.Personally I would recommend ignoring the sections dealing with WRML (or keep them in mind as a detailed example of one possible way of handling some of the REST issues).As to WRML itself: yuck. It appears to be an attempt to drag in some of the unnecessary complexity of SOAP with little added benefit. Not recommended.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Looking up information about WRML, I can agree, 100%. Ugh. So nasty. So this gets a big fat downvote from me.&lt;/p&gt;
&lt;h3 id=&quot;books-i-want-to-read&quot;&gt;Books I want to read&lt;/h3&gt;
&lt;p&gt;There aren’t any in this category. Should there be? You tell me!&lt;/p&gt;
&lt;h2 id=&quot;web-resources&quot;&gt;Web resources&lt;/h2&gt;
&lt;p&gt;There are so many, this will just be a partial list for now.&lt;/p&gt;
&lt;p&gt;Of course, &lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm&quot;&gt;Fielding’s dissertation&lt;/a&gt; is essential.&lt;/p&gt;
&lt;p&gt;Roy has also written &lt;a href=&quot;http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven&quot;&gt;REST APIs Must be Hypertext Driven&lt;/a&gt;. This post is central for understanding why “Hypermedia API” is a much better name than REST, and why hypermedia in general is so essential.&lt;/p&gt;
&lt;p&gt;I’ve written &lt;a href=&quot;http://timelessrepo.com/haters-gonna-hateoas&quot;&gt;this post about HATEOAS&lt;/a&gt;. It’s a pretty basic, simple introduction to the topic.&lt;/p&gt;
&lt;p&gt;I gave a talk called &lt;a href=&quot;http://vimeo.com/30764565&quot;&gt;Everything you know about REST is wrong&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://vimeo.com/20781278&quot;&gt;This talk by Jon Moore&lt;/a&gt; was instrumental in giving me a mental breakthrough about HATEAOS. He was kind enough to &lt;a href=&quot;https://gist.github.com/1445773&quot;&gt;share some code with me&lt;/a&gt; that he used in the presentation as well. This is also an earlier example of the usage of “Hypermedia APIs.”&lt;/p&gt;
&lt;p&gt;A classic: &lt;a href=&quot;http://tomayko.com/writings/rest-to-my-wife&quot;&gt;How I explained REST to my wife&lt;/a&gt;. A great story, simple and easy to explain.&lt;/p&gt;
&lt;p&gt;Another classic is &lt;a href=&quot;http://www.infoq.com/articles/webber-rest-workflow&quot;&gt;How to GET a cup of coffee&lt;/a&gt;. It does a great job of explaining how to model your business processes as state machines, and then convert them to HTTP.&lt;/p&gt;
&lt;p&gt;In which Mike Mayo has a realization that HATEOAS is not simply academic: &lt;a href=&quot;http://mikemayo.org/2012/how-i-learned-to-stop-worrying-and-love-rest&quot;&gt;http://mikemayo.org/2012/how-i-learned-to-stop-worrying-and-love-rest&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A recent resource that’s popped up is &lt;a href=&quot;http://publish.luisrei.com/rest.html&quot;&gt;Designing a RESTful Web API&lt;/a&gt;. It’s a nice, basic overview of lots of things.&lt;/p&gt;
&lt;h2 id=&quot;related-resources&quot;&gt;Related resources&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/1449308929/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=1449308929&quot;&gt;APIs: A Strategy Guide&lt;/a&gt; seems really interesting. This isn’t about REST or Hypermedia APIs specifically, but more making a case for why you’d want an API in the first place. Which is a related topic for all of us API enthusiasts, for sure. I haven’t read it yet, but it’s on the related list.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/0262572338/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=0262572338&quot;&gt;Protocol: How Control Exists after Decentralization&lt;/a&gt; is one of my favorite books ever. This book manages to be both a hard computer science book as well as referencing a broad range of philosophy, history, and other fields as well.&lt;/p&gt;
&lt;p&gt;If sentences like&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A perfect exmaple of a distributed network is the rhizome described in Deleuze and Guattari’s A Thousand Plateaus. Reacting specifically to what they see as the totalitarianism inherent in centralized and even decentralized networks, Deleuze and Guattari instead describe the rhizome, a horizontal meshwork derived from botany. The rhizome links many autonomous nodes together in a manner that is neither linear nor hierarchical. Rhizomes are heterogeneous and connective, that is to say, “Any point of a rhizome can be connected to anything other.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;immediately followed by a hardcore, low-level diagram of the four levels of networking: application layer, transport layer, internet layer, and link layer. With full (and accurate) descriptions of TCP, IP, DNS, the SYN-ACK/SYN-ACK handshake, and HTTP following gets you all hot and bothered, you &lt;em&gt;need&lt;/em&gt; to read this book. Hell, if you don’t like literature stuff, the politics in this book are amazing. This book draws the connections between &lt;em&gt;why&lt;/em&gt; the APIs we’re building matter, and for that matter, the systems that we programmers create. Seriously, I can’t recommend this book enough.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/0801882575/ref=as_li_ss_tl?ie=UTF8&amp;#x26;tag=stesblo026-20&amp;#x26;linkCode=as2&amp;#x26;camp=1789&amp;#x26;creative=390957&amp;#x26;creativeASIN=0801882575&quot;&gt;Hypertext 3.0: Critical Theory and New Media in an Era of Globalization&lt;/a&gt; is related, and absolutely interesting. Here’s the eight main sections:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hypertext: An introduction&lt;/li&gt;
&lt;li&gt;Hypertext and Critical Theory&lt;/li&gt;
&lt;li&gt;Reconfiguring the Text&lt;/li&gt;
&lt;li&gt;Reconfiguring the Author&lt;/li&gt;
&lt;li&gt;Reconfiguring Writing&lt;/li&gt;
&lt;li&gt;Reconfiguring Narrative&lt;/li&gt;
&lt;li&gt;Reconfiguring Literary Education&lt;/li&gt;
&lt;li&gt;The Politics of Hypertext: Who Controls the Text?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While not &lt;em&gt;directly&lt;/em&gt; useful for those designing APIs, those of us who like to draw broad connections between disciplines will find that this book has lots of interesting parallels. Especially around the politics angle, as well as reconfiguring narrative.&lt;/p&gt;</content:encoded></item><item><title>REST is over</title><link>https://steveklabnik.com/writing/rest-is-over/</link><guid isPermaLink="true">https://steveklabnik.com/writing/rest-is-over/</guid><description>REST is Yep. Sorry to have to inform you. REST is totally over. The cool kids are moving on. We’re building “Hypermedia APIs” now. Such is life. A lesson from the anti-globalization movement Way back in the day, COINTELPRO was at the forefront of America’s fight against…</description><pubDate>Thu, 23 Feb 2012 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;rest-is&quot;&gt;REST is&lt;/h1&gt;
&lt;p&gt;&lt;img alt=&quot;Rest is OVER&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;620&quot; height=&quot;333&quot; src=&quot;/_astro/restisover.BEVKiPMJ_ZNWDRS.webp&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Yep. Sorry to have to inform you. REST is totally over. The cool kids are moving on. We’re building “Hypermedia APIs” now. Such is life.&lt;/p&gt;
&lt;h2 id=&quot;a-lesson-from-the-anti-globalization-movement&quot;&gt;A lesson from the anti-globalization movement&lt;/h2&gt;
&lt;p&gt;Way back in the day, &lt;a href=&quot;http://en.wikipedia.org/wiki/COINTELPRO&quot;&gt;COINTELPRO&lt;/a&gt; was at the forefront of America’s fight against “subersive” organizations and individuals. One goal of COINTELPRO was to create tension and division amongst radical groups, in order to disrupt their operations. Techniques such as Concern Trolling are really effective at this kind of thing.&lt;/p&gt;
&lt;p&gt;In 2008, for the Republican National Convention in St. Paul, a document was passed around:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At an anti-RNC conference held over the weekend of February 9th and 10th, a broad spectrum of groups revealed what are being called the “St. Paul Principles” of unity for resisting the 2008 Republican National Convention (RNC).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a departure from the sectarian squabbles that have plagued past years’ anti-convention organizing. Pitting groups of differing political beliefs against each other has been a frequent tactic of state repression since the days of COINTELPRO.&lt;/p&gt;
&lt;p&gt;By drafting the principles together, the co-signing organizations are taking historic steps to actively extinguish divisiveness from their respective groups. The principles will ensure respect for the soon-to-be-permitted march on September 1 by people planning non-permitted activities, and in turn, participants in the September 1 march will adhere to the principles and do nothing to sow division among the many activists coming to the Twin Cities to protest the RNC.&lt;/p&gt;
&lt;p&gt;The principles are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Our solidarity will be based on respect for a diversity of tactics and the plans of other groups.&lt;/li&gt;
&lt;li&gt;The actions and tactics used will be organized to maintain a separation of time or space.&lt;/li&gt;
&lt;li&gt;Any debates or criticisms will stay internal to the movement, avoiding any public or media denunciations of fellow activists and events.&lt;/li&gt;
&lt;li&gt;We oppose any state repression of dissent, including surveillance, infiltration, disruption and violence. We agree not to assist law enforcement actions against activists and others.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Please draw your attention to the third principle. The reasons behind this rule are interesting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;‘Solidarity’ kinda goes out the window when you’re busy arguing about each other’s drama.&lt;/li&gt;
&lt;li&gt;Every second you have in the media is precious. Why waste it talking about each other when you could be talking about your issue?&lt;/li&gt;
&lt;li&gt;Media will jump on any kind of debate as a weakness. The only way to make these sort of self-reflective discussions productive is to keep them internal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, keeping that all in mind, why are we arguing about what REST means all the time? Yes, it’s annoying that the common usage of REST is not actually REST. Yes, it’s really hard when someone is wrong on the Internet. Yes, words do matter. However, it’s a question of what’s most productive with our time. Every moment we waste arguing over what REST means could have been spent discussing how to properly build APIs instead. But why bother being productive when we can be critical?&lt;/p&gt;
&lt;h2 id=&quot;hypermedia-api-is-more-clear&quot;&gt;‘Hypermedia API’ is more clear&lt;/h2&gt;
&lt;p&gt;The real problem is that REST is just bad branding. This isn’t Roy’s fault, he wasn’t thinking about such things when trying to write his thesis. But really, from an outside perspective, a ‘real RESTful API’ does two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Uses HTTP correctly.&lt;/li&gt;
&lt;li&gt;Serves hypermedia responses.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;HTTP does most of the heavy lifting in terms of bringing us into REST compliance. So why are we talking about how to transfer representations of state?&lt;/p&gt;
&lt;p&gt;The phrase “Hypermedia API” is much more direct: it’s an API where hypermedia is at the center. Those RESTish APIs could never be called ‘Hypermedia APIs,’ as it’s quite obvious that they don’t use hypermedia. It is not quite clear that they don’t transfer state and representations, though. ;)&lt;/p&gt;
&lt;h2 id=&quot;we-just-really-shouldnt-fight&quot;&gt;We just really shouldn’t fight&lt;/h2&gt;
&lt;p&gt;Ultimately, it really comes back to the first point, though. Arguing about this is just wasting everyone’s time. It’s time to take a deep breath, step back, and just let REST go. Language changes. It happens. It might be a little bit sad, but life will move on. Let’s build fantastic APIs instead. &amp;#x3C;3 &amp;#x3C;3 &amp;#x3C;3&lt;/p&gt;
&lt;p&gt;Oh, and I didn’t actually kick this off, credit for that goes to Mike Amundsen and O’Reilly with &lt;a href=&quot;http://www.amazon.com/Building-Hypermedia-APIs-HTML5-Node/dp/1449306578/ref=sr_1_1?ie=UTF8&amp;#x26;qid=1330039178&amp;#x26;sr=8-1&quot;&gt;Building Hypermedia APIs with HTML5 and Node&lt;/a&gt;. Once something has an O’Reilly book about it, it’s legit. ;) Additionally, the term has been bandied about in the past, in various presentations and talks, but I feel that now’s the time to really step forward and start calling a spade a spade.&lt;/p&gt;</content:encoded></item><item><title>An API ontology</title><link>https://steveklabnik.com/writing/an-api-ontology/</link><guid isPermaLink="true">https://steveklabnik.com/writing/an-api-ontology/</guid><description>NOTE : The alpha of my book on APIs is out! Check it out at http://designinghypermediaapis.com . As I’ve done research on APIs for Designing Hypermedia APIs , I’ve become increasingly interested in different styles of API. I currently see most real-world deployed APIs fit into a…</description><pubDate>Mon, 13 Feb 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: The alpha of my book on APIs is out! Check it out at &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;http://designinghypermediaapis.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I’ve done research on APIs for &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;Designing Hypermedia APIs&lt;/a&gt;, I’ve become increasingly interested in different styles of API. I currently see most real-world deployed APIs fit into a few different categories. All have their pros and cons, and it’s important to see how they relate to one other.&lt;/p&gt;
&lt;p&gt;You may find this amusing if you’ve &lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/net_arch_styles.htm&quot;&gt;read some of the literature&lt;/a&gt; on the topic, but I’ve created this list in a top-down way: APIs as black boxes, rather than coming up with different aspects of an API and categorizing them based on that. I also decided to look at actually deployed APIs, rather than theoretical software architectures.&lt;/p&gt;
&lt;p&gt;If you have an API that doesn’t fit into one of these categories, I’d love to hear about it. I’d also like to further expand these descriptions, if you have suggestions in that regard, please drop me a line, too.&lt;/p&gt;
&lt;h2 id=&quot;http-getpost&quot;&gt;HTTP GET/POST&lt;/h2&gt;
&lt;h3 id=&quot;synopsis&quot;&gt;Synopsis:&lt;/h3&gt;
&lt;p&gt;Provide simple data through a simple GET/POST request.&lt;/p&gt;
&lt;h3 id=&quot;examples&quot;&gt;Examples:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://placekitten.com/&quot;&gt;http://placekitten.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://code.google.com/apis/maps/documentation/staticmaps/&quot;&gt;http://code.google.com/apis/maps/documentation/staticmaps/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://loripsum.net/api&quot;&gt;http://loripsum.net/api&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;description&quot;&gt;Description:&lt;/h3&gt;
&lt;p&gt;Simple data is made available via an HTTP GET or POST request. The vast majority of these services seem to return images, but data is possible as well.&lt;/p&gt;
&lt;p&gt;These API are technically a sub-type of *-RPC, but I feel that their lack of business process makes them feel different. It’s basically just one specific remote procedure, available over HTTP.&lt;/p&gt;
&lt;h2 id=&quot;-rpc&quot;&gt;*-RPC&lt;/h2&gt;
&lt;h3 id=&quot;synopsis-1&quot;&gt;Synopsis:&lt;/h3&gt;
&lt;p&gt;Remote procedure call; call a function over the web.&lt;/p&gt;
&lt;h3 id=&quot;examples-1&quot;&gt;Examples:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://codex.wordpress.org/XML-RPC_Support&quot;&gt;http://codex.wordpress.org/XML-RPC_Support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.flickr.com/services/api/request.rest.html&quot;&gt;http://www.flickr.com/services/api/request.rest.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://services.sunlightlabs.com/docs/Sunlight_Congress_API/&quot;&gt;http://services.sunlightlabs.com/docs/Sunlight_Congress_API/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;description-1&quot;&gt;Description:&lt;/h3&gt;
&lt;p&gt;Similiar to how structured programming is built around functions, so is RPC. Rather than call functions from your own programs, RPC is a way to call functions over the Internet.&lt;/p&gt;
&lt;p&gt;All calls are made through some sort of API endpoint, and usually sent over HTTP POST.&lt;/p&gt;
&lt;p&gt;Major flavors include XML-RPC and JSON-RPC, depending on what format data is returned in.&lt;/p&gt;
&lt;p&gt;Note that while Flickr’s API says REST, it is very clearly RPC. Yay terminology!&lt;/p&gt;
&lt;h2 id=&quot;ws--or-soap&quot;&gt;WS-* (or SOAP)&lt;/h2&gt;
&lt;h3 id=&quot;synopsis-2&quot;&gt;Synopsis:&lt;/h3&gt;
&lt;p&gt;Serialize and send objects over the wire.&lt;/p&gt;
&lt;h3 id=&quot;examples-2&quot;&gt;Examples:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.flickr.com/services/api/request.soap.html&quot;&gt;http://www.flickr.com/services/api/request.soap.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&amp;#x26;content_ID=developer/e_howto_api_soap_PayPalSOAPAPIArchitecture&quot;&gt;https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&amp;#x26;content_ID=developer/e_howto_api_soap_PayPalSOAPAPIArchitecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_quickstart_intro.htm&quot;&gt;http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_quickstart_intro.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;description-2&quot;&gt;Description:&lt;/h3&gt;
&lt;p&gt;SOAP stands for “Simple Object Access Protocol,” and that describes it pretty well. The idea behind these APIs is to somehow serialize your objects and then send them over the wire to someone else.&lt;/p&gt;
&lt;p&gt;This is usually accomplished by downloading a WSDL file, which your IDE can then use to generate a whole ton of objects. You can then treat these as local, and the library will know how to make the remote magic happen.&lt;/p&gt;
&lt;p&gt;These are much more common in the .NET world, and have fallen out of favor in startup land. Many larger businesses still use SOAP, though, due to tight integration with the IDE.&lt;/p&gt;
&lt;h2 id=&quot;rest&quot;&gt;“REST”&lt;/h2&gt;
&lt;h3 id=&quot;synopsis-3&quot;&gt;Synopsis:&lt;/h3&gt;
&lt;p&gt;Ruby on Rails brought respect for HTTP into the developer world. A blending of RPC, SOAP, and hypermedia API types.&lt;/p&gt;
&lt;h3 id=&quot;examples-3&quot;&gt;Examples:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://developer.github.com/&quot;&gt;http://developer.github.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.twitter.com/&quot;&gt;https://dev.twitter.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://developers.facebook.com/docs/reference/api/&quot;&gt;http://developers.facebook.com/docs/reference/api/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;description-3&quot;&gt;Description:&lt;/h3&gt;
&lt;p&gt;Originally, REST was synonymous with what is now called “Hypermedia APIs.” However, after large amounts of misunderstanding, REST advocates are rebranding REST to “Hypermedia APIs” and leaving REST to the RESTish folks. See ’&lt;a href=&quot;/posts/2012-02-23-rest-is-over&quot;&gt;REST is over’&lt;/a&gt; for more.&lt;/p&gt;
&lt;p&gt;REST is basically “RPC and/or SOAP that respects HTTP.” A large problem with RPC and SOAP APIs is that they tunnel everything through one endpoint, which means that they can’t take advantage of many features of HTTP, like auth and caching. RESTful APIs mitigate this disadvantage by adding lots of endpoints; one for each ‘resource.’ The SOAPish ones basically allow you to CRUD objects over HTTP by using tooling like ActiveResource, and the RPC ones let you perform more complicated actions, but always with different endpoints.&lt;/p&gt;
&lt;h2 id=&quot;hypermedia&quot;&gt;Hypermedia&lt;/h2&gt;
&lt;h3 id=&quot;synopsis-4&quot;&gt;Synopsis:&lt;/h3&gt;
&lt;p&gt;Hypermedia is used to drive clients through various business processes. The least understood and deployed API type, with one exception: the World Wide Web.&lt;/p&gt;
&lt;h3 id=&quot;examples-4&quot;&gt;Examples:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.twilio.com/docs/api/rest&quot;&gt;http://www.twilio.com/docs/api/rest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.spire.io/docs/tutorials/rest-api.html&quot;&gt;http://www.spire.io/docs/tutorials/rest-api.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://kenai.com/projects/suncloudapis/pages/Home&quot;&gt;http://kenai.com/projects/suncloudapis/pages/Home&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;description-4&quot;&gt;Description:&lt;/h3&gt;
&lt;p&gt;Originally called REST, Hypermedia APIs take full advantage of HTTP. They use hypermedia formats to drive business processes, providing the ultimate decoupling of clients and servers.&lt;/p&gt;
&lt;p&gt;You can tell an API is Hypermedia by providing only one API endpoint, but which accepts requests at other endpoints that are provided by discovery. You navigate through the API by letting the server’s responses guide you.&lt;/p&gt;</content:encoded></item><item><title>Implementing HATEOS with presenters</title><link>https://steveklabnik.com/writing/implementing-hateoas-with-presenters/</link><guid isPermaLink="true">https://steveklabnik.com/writing/implementing-hateoas-with-presenters/</guid><description>I’m a big fan of using the presenter pattern to help separate logic from presentation. There’s a great gem named Draper that can help facilitate this pattern in your Rails apps. When doing research for my book about REST , I realized that the presenter pattern is a great way to…</description><pubDate>Fri, 06 Jan 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m a big fan of using the presenter pattern to help separate logic from presentation. There’s a great gem named &lt;a href=&quot;https://github.com/jcasimir/draper&quot;&gt;Draper&lt;/a&gt; that can help facilitate this pattern in your Rails apps. When doing research for &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;my book about REST&lt;/a&gt;, I realized that the presenter pattern is a great way to create responses that comply with the hypermedia constraint, a.k.a. HATEOAS. I wanted to share with you a little bit about how to do this.&lt;/p&gt;
&lt;p&gt;Please note that ’&lt;a href=&quot;/posts/2012-02-23-rest-is-over&quot;&gt;REST is over’&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note: We’ll be creating HTML5 responses in this example, as HTML is a hypermedia format, and is therefore conducive to HATEOAS. JSON and XML don’t cut it.&lt;/p&gt;
&lt;h2 id=&quot;first-some-setup&quot;&gt;First, some setup&lt;/h2&gt;
&lt;p&gt;I fired up a brand new Rails app by doing this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ rails new hateoas_example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ cd hateoas_example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ cat &gt;&gt; Gemfile&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;gem &quot;draper&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;^D&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ bundle&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ rails g resource post title:string body:text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ rake db:migrate&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ rails g draper:decorator Post&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, now we should be all set up. We’ve got a Rails app, it’s got draper in the Gemfile, we have a Post resource, and our PostDecorator.&lt;/p&gt;
&lt;h2 id=&quot;the-view&quot;&gt;The View&lt;/h2&gt;
&lt;p&gt;I like to do the view first, to drive our what we need elsewhere. Here it is:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;h2&gt;Title&amp;#x3C;/h2&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;p&gt;&amp;#x3C;%= @post.title %&gt;&amp;#x3C;/p&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;h2&gt;Body&amp;#x3C;/h2&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;p&gt;&amp;#x3C;%= @post.body %&gt;&amp;#x3C;/p&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;h2&gt;Links&amp;#x3C;/h2&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;ul&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;% @post.links.each do |link| %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;li&gt;&amp;#x3C;%= link_to link.text, link.href, :rel =&gt; link.rel %&gt;&amp;#x3C;/li&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;% end %&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/ul&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re displaying our title and body, but we also want to spit out some links. These links should have a few attributes we need. I might even (shhhhhhh) extract this link thing out into a helper to add the rel stuff every time. It just depends. For this example, I didn’t feel like it.&lt;/p&gt;
&lt;h2 id=&quot;the-controller&quot;&gt;The Controller&lt;/h2&gt;
&lt;p&gt;Well, we know we’re gonna need a &lt;code&gt;@post&lt;/code&gt; variable set, so let’s get that going in our controller:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PostsController&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ApplicationController&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; show&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @post &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; PostDecorator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(params[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Super simple. Yay Draper!&lt;/p&gt;
&lt;h2 id=&quot;the-presenter&quot;&gt;The Presenter&lt;/h2&gt;
&lt;p&gt;We know we need a &lt;code&gt;links&lt;/code&gt; method that returns some links, and those links need to have rel, href, and text attributes. No problem!&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Struct&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:rel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:href&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:text&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; PostDecorator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ApplicationDecorator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  decorates &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;:post&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; links&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    [self_link, all_posts_link]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; all_posts_link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, h.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;posts_url&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;All posts&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  def&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; self_link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    Link&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;self&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, h.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;post_url&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(post), &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;This post&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we could have just returned an array of three-element arrays, but I really like to use the Struct.new trick to give us an actual class. It makes error messages quite a bit better, and reminds us that we don’t happen to have an array, we have a Link.&lt;/p&gt;
&lt;p&gt;We construct those links by taking advantage of the ‘index’ and ‘self’ rel attributes that are &lt;a href=&quot;http://www.iana.org/assignments/link-relations/link-relations.xml&quot;&gt;defined in the registry&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-output&quot;&gt;The output&lt;/h2&gt;
&lt;p&gt;That gives us this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;!&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;DOCTYPE&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; html&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;HateoasSample&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/assets/application.css?body=1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;screen&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/css&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/assets/posts.css?body=1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; media&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;screen&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/css&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/assets/jquery.js?body=1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/assets/jquery_ujs.js?body=1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/assets/posts.js?body=1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/assets/application.js?body=1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;authenticity_token&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;csrf-param&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;meta&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;0k+SQVv6yr0d12tGWYx7KNXUWaf6f+wgUUNITsAOnHI=&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;csrf-token&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Title&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;A post, woo hoo!&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Body&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;this is some text that&apos;s the body of this post&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;Links&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;http://localhost:3000/posts/1&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;self&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;This post&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;http://localhost:3000/posts&quot;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;All posts&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;li&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;ul&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;html&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll probably want to make a layout that ignores all of the JS stuff, but for this example, I just left it as-is. It’s just that easy. Happy linking!&lt;/p&gt;</content:encoded></item><item><title>Write better cukes with the rel attribute</title><link>https://steveklabnik.com/writing/write-better-cukes-with-the-rel-attribute/</link><guid isPermaLink="true">https://steveklabnik.com/writing/write-better-cukes-with-the-rel-attribute/</guid><description>The other day, I was working on some Cucumber features for a project, and I discovered a neat technique that helps you to write better Cucumber steps. Nobody wants to be cuking it wrong , but what does that really mean? Here’s Jonas’ prescription: A step description should never…</description><pubDate>Tue, 20 Dec 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The other day, I was working on some Cucumber features for a project, and I discovered a neat technique that helps you to write better Cucumber steps.&lt;/p&gt;
&lt;p&gt;Nobody wants to be &lt;a href=&quot;http://elabs.se/blog/15-you-re-cuking-it-wrong&quot;&gt;cuking it wrong&lt;/a&gt;, but what does that really mean? Here’s Jonas’ prescription:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A step description should never contain regexen, CSS or XPath selectors, any kind of code or data structure. It should be easily understood just by reading the description.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great. Let’s &lt;a href=&quot;http://www.theregister.co.uk/2007/06/25/thoughtworks_req_manage/&quot;&gt;pop the why stack&lt;/a&gt; a few times, shall we?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q1&lt;/strong&gt;: Why do we want to have descriptions not use regexen, CSS selectors, or code? &lt;strong&gt;A1&lt;/strong&gt;: To give it a simpler language.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q2&lt;/strong&gt;: Why do we want it to be in a simpler language? &lt;strong&gt;A2&lt;/strong&gt;: So that it’s easily understandable for stakeholders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q3&lt;/strong&gt;: Why do we want it to be easily understandable for stakeholders? &lt;strong&gt;A3&lt;/strong&gt;: Because then we can share a &lt;a href=&quot;http://domaindrivendesign.org/node/132&quot;&gt;common language&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q4&lt;/strong&gt;: Why is a common language important? &lt;strong&gt;A4&lt;/strong&gt;: A shared language assists in making sure our model matches the desires of our stakeholders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q5&lt;/strong&gt;: Why do we want to match the desires of our stakeholders? &lt;strong&gt;A5&lt;/strong&gt;: That’s the whole reason we’re on this project in the first place!&lt;/p&gt;
&lt;p&gt;Anyway, that’s what it’s really all about: developing that common language. Cukes should be written in that common language so that we can make sure we’re on track. So fine: common language. Awesome. Let’s do this.&lt;/p&gt;
&lt;h2 id=&quot;write-some-cukes-in-common-language&quot;&gt;Write some cukes in common language&lt;/h2&gt;
&lt;p&gt;Time to write a cuke:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Scenario: Editing the home page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Given I&apos;m logged in as an administrator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  When I go to the home page&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  And I choose to edit the article&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  And I fill in some content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  And I save it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  Then I should see that content&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basic CMS style stuff. I’m not going to argue that this is the best cuke in the world, but it’s pretty good. What I want to do is examine some of these steps in more detail. How would you implement these steps?&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;When&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; /^I choose to edit the article$/&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pending&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;When&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; /^I fill in some content$/&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pending&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;When&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; /^I save it$/&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pending&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Then&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; /^I should see that content$/&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pending&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go ahead. Write them down somewhere. I’ll wait.&lt;/p&gt;
&lt;p&gt;… done yet?&lt;/p&gt;
&lt;h2 id=&quot;implementing-a-step&quot;&gt;Implementing a step&lt;/h2&gt;
&lt;p&gt;Done? Okay! Before I show you my implementation, let’s talk about this step:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;When&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; /^I choose to edit the article$/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When writing this step, I realized something. When trying to write steps like these, there’s a danger in tying them too closely to your specific HTML. It’s why many people don’t write view tests: they’re brittle. I actually like view tests, but that’s another blog post. Point is this: we know we’re going to follow a link, and we know that we want that link to go somewhere that will let us edit the article. We don’t really care &lt;em&gt;where&lt;/em&gt; it is in the DOM, just that somewhere, we’ve got an ‘edit article’ link. How to pull this off?&lt;/p&gt;
&lt;h3 id=&quot;first-idea-id-attribute&quot;&gt;First idea: id attribute&lt;/h3&gt;
&lt;p&gt;You might be thinking “I’ll give it an id attribute!” Here’s the problem with that: ids have to be unique, per page. With article editing, that might not be a problem, but it’s certainly not a general solution. So that’s out.&lt;/p&gt;
&lt;h3 id=&quot;second-time-class-attribute&quot;&gt;Second time: class attribute&lt;/h3&gt;
&lt;p&gt;“Okay, then just use a class. Your blog sucks.” Well, let’s check out what &lt;a href=&quot;http://www.w3.org/TR/html5/elements.html#classes&quot;&gt;the HTML5 spec says about classes&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Basically nothing about semantics.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay, so that’s paraphrased. But still, the spec basically says some stuff about the details of implementing classes, but absolutely nothing about the semantics of a class. In practice, classes are largely used for styling purposes. We don’t want to conflate our styling with our data, so overloading class for this purpose might work, but feels kinda wrong.&lt;/p&gt;
&lt;h3 id=&quot;what-about-the-text&quot;&gt;What about the text?&lt;/h3&gt;
&lt;p&gt;We could match on the text of the link. After all, that’s what people use to determine what links to click on. The link with the text “Edit this article” lets us know that that link will let us edit a article.&lt;/p&gt;
&lt;p&gt;Matching on the text is brittle, though. What happens when marketing comes through and changes the text to read “Edit my article”? Our tests break. Ugh.&lt;/p&gt;
&lt;p&gt;There’s got to be a better way. Otherwise, I wouldn’t be writing this blog post.&lt;/p&gt;
&lt;h3 id=&quot;the-best-way-the-rel-attribute&quot;&gt;The best way: the rel attribute&lt;/h3&gt;
&lt;p&gt;When doing research for &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;my book on REST&lt;/a&gt;, I’ve been doing a lot of digging into various standards documents. And one of the most important attributes from a REST perspective is one that nobody ever talks about or uses: the &lt;code&gt;rel&lt;/code&gt; attribute. From &lt;a href=&quot;http://www.w3.org/TR/html5/links.html#attr-hyperlink-rel&quot;&gt;the HTML5 spec&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The rel attribute on a and area elements controls what kinds of links the elements create. The attribue’s value must be a set of space-separated tokens. The allowed keywords and their meanings are defined below.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Below? That’s &lt;a href=&quot;http://www.w3.org/TR/html5/links.html#linkTypes&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The following table summarizes the link types that are defined by this specification. This table is non-normative; the actual definitions for the link types are given in the next few sections.alternate: Gives alternate representations of the current document. author: Gives a link to the current document’s author. bookmark: Gives the permalink for the nearest ancestor section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Hey now! Seems like we’re on to something. There’s also &lt;a href=&quot;http://tools.ietf.org/html/rfc5988&quot;&gt;RFC 5988&lt;/a&gt;, “Web Linking”. &lt;a href=&quot;http://tools.ietf.org/html/rfc5988#section-4&quot;&gt;Section four&lt;/a&gt; talks about Link Relation Types:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the simplest case, a link relation type identifies the semantics of a link. For example, a link with the relation type “copyright” indicates that the resource identified by the target IRI is a statement of the copyright terms applying to the current context IRI.Link relation types can also be used to indicate that the target resource has particular attributes, or exhibits particular behaviours; for example, a “service” link implies that the identified resource is part of a defined protocol (in this case, a service description).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Bam! Awesome! This is exactly what we want!&lt;/p&gt;
&lt;h2 id=&quot;so-how-do-we-use-rel-attributes&quot;&gt;So how do we use rel attributes?&lt;/h2&gt;
&lt;p&gt;I’ll be going into more depth about these kinds of topics in &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;my book&lt;/a&gt;, but here’s the TL;DR:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There are a set of official types. Try to use those if they’re applicable, but they’re quite general, so that’s often not the case.&lt;/li&gt;
&lt;li&gt;You can put whatever else you want. Space delineated. *&lt;/li&gt;
&lt;li&gt;The best way is to use a URI and then make a resource at that URI that documents the relation’s semantics.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’ll go with option two for now, for simplicity. In a real application, make it a URI.&lt;/p&gt;
&lt;p&gt;(*) Technically, this isn’t true. Extension relations are &lt;em&gt;required&lt;/em&gt; to be URIs, or something that can be serialized to a URI. Again, details are outside of the scope of this post.&lt;/p&gt;
&lt;h2 id=&quot;making-our-link-with-semantics&quot;&gt;Making our link, with semantics.&lt;/h2&gt;
&lt;p&gt;Here’s what a link with our newly minted relation looks like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;a href=&quot;/articles/1/edit&quot; rel=&quot;edit-article&quot;&gt;Edit this article&amp;#x3C;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Super simple. Just that one little attribute. Now we can write a step to match:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ruby&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;When&lt;/span&gt;&lt;span style=&quot;color:#DBEDFF&quot;&gt; /^I choose to edit the article$/&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  find&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;//a[@rel=&apos;edit-article&apos;]&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;click&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code matches what we’d do as a person really well. “Find the link that edits an article, and click on it.” We’ve not only made the title of our step match our idea of what a person would do, but the code has followed suit. Awesome. We can move this link anywhere on the page, our test doesn’t break. We can change the text of the link, and our test doesn’t break. So cool.&lt;/p&gt;
&lt;h2 id=&quot;what-about-stuff-thats-not-links-what-about-data-attributes&quot;&gt;What about stuff that’s not links? What about data attributes?&lt;/h2&gt;
&lt;p&gt;That’s what &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;my book&lt;/a&gt; is going to talk about, sorry. These kinds of practical examples are one of the reasons I decided to write it in the first place, and I don’t want to publish all the content on my blog…&lt;/p&gt;
&lt;h2 id=&quot;better-tests-through-web-standards&quot;&gt;Better tests through web standards&lt;/h2&gt;
&lt;p&gt;Turns out that diving around in standards has some practical benefits after all, eh? Think about the relationship between your cukes, your tests, and your API clients: Cucumber, through Selenium, is an automated agent that interacts with your web service. API clients are automated agents that interact with your web service. Hmmmm…&lt;/p&gt;
&lt;p&gt;If you want to know more about this, that’s what &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;my book&lt;/a&gt; is for. I’ll be covering topics like this in depth, and explaining standards in simple language.&lt;/p&gt;
&lt;p&gt;Seriously. Did you sign up for &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;my book&lt;/a&gt; yet? ;)&lt;/p&gt;</content:encoded></item><item><title>Some people understand REST and HTTP</title><link>https://steveklabnik.com/writing/some-people-understand-rest-and-http/</link><guid isPermaLink="true">https://steveklabnik.com/writing/some-people-understand-rest-and-http/</guid><description>This is a follow-up post to my post here . You probably want to read that first. UPDATE: Please note that ‘ REST is over’ . ’Hypermedia API’ is the proper term now. A few words on standards versus pragmatism When I wrote my first post on this topic, I tried to take a stance that…</description><pubDate>Sun, 07 Aug 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a follow-up post to my post &lt;a href=&quot;/writing/nobody-understands-rest-or-http/&quot;&gt;here&lt;/a&gt;. You probably want to read that first.&lt;/p&gt;
&lt;p&gt;UPDATE: Please note that ‘&lt;a href=&quot;/posts/2012-02-23-rest-is-over&quot;&gt;REST is over’&lt;/a&gt;. ’Hypermedia API’ is the proper term now.&lt;/p&gt;
&lt;h2 id=&quot;a-few-words-on-standards-versus-pragmatism&quot;&gt;A few words on standards versus pragmatism&lt;/h2&gt;
&lt;p&gt;When I wrote my first post on this topic, I tried to take a stance that would be somewhat soft, yet forceful. Engineering is the art of making the proper trade-offs, and there are times when following specifications is simply not the correct decision. With that said, my motivation for both of these posts is to eradicate some of the ignorance that some developers have about certain areas of the HTTP spec and Fielding’s REST paper. If you understand the correct way, yet choose to do something else for an informed reason, that’s absolutely, 100% okay. There’s no use throwing out the baby with the bathwater. But ignorance is never a good thing, and most developers are ignorant when it comes to the details of REST.&lt;/p&gt;
&lt;p&gt;Secondly, while I think that REST is the best way to develop APIs, there are other valid architectural patterns, too. Yet calling non-REST APIs ‘RESTful’ continues to confuse developers as to what “RESTful” means. I’m not sure what exactly we should call “RESTish” APIs (hey, there we go, hmmm…) but I’m also not under the illusion that I personally will be able to make a huge dent in this. Hopefully you, humble reader, will remember this when dealing with APIs in the future, and I’ll have made a tiny dent, though.&lt;/p&gt;
&lt;h2 id=&quot;so-who-does-understand-rest&quot;&gt;So who &lt;em&gt;does&lt;/em&gt; understand REST?&lt;/h2&gt;
&lt;p&gt;As it turns out, there are two companies that you’ve probably heard of who have APIs that are much more RESTful than many others: &lt;a href=&quot;http://www.twilio.com/docs/api/rest/&quot;&gt;Twilio&lt;/a&gt; and &lt;a href=&quot;http://developer.github.com/&quot;&gt;GitHub&lt;/a&gt;. Let’s take a look at GitHub first.&lt;/p&gt;
&lt;h3 id=&quot;github-logically-awesome&quot;&gt;GitHub: logically awesome&lt;/h3&gt;
&lt;p&gt;GitHub’s developer resources are not only beautiful, but thorough. In addition, they make use of lots more of REST.&lt;/p&gt;
&lt;h3 id=&quot;the-good&quot;&gt;The good&lt;/h3&gt;
&lt;p&gt;GitHub uses &lt;a href=&quot;http://developer.github.com/v3/mime/&quot;&gt;custom MIME&lt;/a&gt; types for all of their responses. They’re using the vendor extensions that I talked about in my post, too. For example:&lt;/p&gt;
&lt;p&gt;application/vnd.github-issue.text+json&lt;/p&gt;
&lt;p&gt;Super cool.&lt;/p&gt;
&lt;p&gt;Their &lt;a href=&quot;http://developer.github.com/v3/#authentication&quot;&gt;authentication&lt;/a&gt; works in three ways: HTTP Basic, OAuth via an Authentication Header, or via a parameter. This allows for a maximum amount of compatibility across user agents, and gives the user some amount of choice.&lt;/p&gt;
&lt;p&gt;Their &lt;a href=&quot;http://developer.github.com/v3/#pagination&quot;&gt;Pagination&lt;/a&gt; uses a header I didn’t discuss in part I: the Link header. &lt;a href=&quot;http://tools.ietf.org/html/rfc5988&quot;&gt;Here&lt;/a&gt;’s a link to the reference. Basically, Link headers enable HATEOAS for media types which aren’t hypertext. This is important, especially regarding JSON, since JSON isn’t hypermedia. More on this at the end of the post. Anyway, so pagination on GitHub:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -I &quot;https://api.github.com/users/steveklabnik/gists&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Server: nginx/1.0.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Date: Sun, 07 Aug 2011 16:34:48 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection: keep-alive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Status: 200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Limit: 5000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Remaining: 4994&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Link: &amp;#x3C;https://api.github.com/users/steveklabnik/gists?page=2&gt;; rel=&quot;next&quot;, &amp;#x3C;https://api.github.com/users/steveklabnik/gists?page=33333&gt;; rel=&quot;last&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Length: 29841&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Link header there shows you how to get to the next page of results. You don’t need to know how to construct the URL, you just have to parse the header and follow it. This, for example, is a great way to connect a resource that’s not text-based, such as a PNG, to other resources.&lt;/p&gt;
&lt;h3 id=&quot;the-bad&quot;&gt;The bad&lt;/h3&gt;
&lt;p&gt;There’s really only one place that GitHub doesn’t knock it out of the park with their new API, and that’s HATEOAS. GitHub’s API isn’t discoverable, because there’s no information at the root:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -I https://api.github.com/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 302 Found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Server: nginx/1.0.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Date: Sun, 07 Aug 2011 16:44:02 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: text/html;charset=utf-8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection: keep-alive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Status: 302 Found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Limit: 5000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Location: http://developer.github.com&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Remaining: 4993&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Length: 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, at least, this is how they present it. If you ask for JSON:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -I https://api.github.com/ -H &quot;Accept: application/json&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 204 No Content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Server: nginx/1.0.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Date: Sun, 07 Aug 2011 16:45:32 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection: keep-alive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Status: 204 No Content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Limit: 5000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Remaining: 4991&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Link: &amp;#x3C;users/{user}&gt;; rel=&quot;user&quot;, &amp;#x3C;repos/{user}/{repo}&gt;; rel=&quot;repo&quot;, &amp;#x3C;gists&gt;; rel=&quot;gists&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You do get Links, but you have to construct things yourself. As a user, you get the same thing. It doesn’t change the links to point to your repos, it doesn’t give you links to anything else that you can do with the API.&lt;/p&gt;
&lt;p&gt;Instead, the root should give you a link to the particular resources that you can actually view. Maybe something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl -I https://api.github.com/ -H &quot;Accept: application/json&quot; -u &quot;username:password&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 204 No Content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Server: nginx/1.0.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Date: Sun, 07 Aug 2011 16:45:32 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connection: keep-alive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Status: 204 No Content&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Limit: 5000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-RateLimit-Remaining: 4991&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Link: &amp;#x3C;/gists/public&gt;; rel=&quot;public_gists&quot;, &amp;#x3C;/user/repos&gt;; rel=&quot;repos&quot;, &amp;#x3C;gists&gt;; rel=&quot;gists&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a bunch more, for all of the other resources that are available. This would make the API truly discoverable, and you wouldn’t be forced to read their gorgeous documentation. :)&lt;/p&gt;
&lt;h3 id=&quot;twilio&quot;&gt;Twilio&lt;/h3&gt;
&lt;p&gt;I’ve always really enjoyed Twilio. Their API is incredibly simple to use. I once hooked up a little “Text me when someone orders something from my site” script, and it took me about fifteen minutes. Good stuff.&lt;/p&gt;
&lt;h3 id=&quot;the-good-1&quot;&gt;The good&lt;/h3&gt;
&lt;p&gt;Twilio has got the HATEOAS thing down. Check it out, their home page says that the base URL is “&lt;a href=&quot;https://api.twilio.com/2010-04-01%E2%80%9D&quot;&gt;https://api.twilio.com/2010-04-01”&lt;/a&gt;. Without looking at any of the rest of their docs, (I glanced at a page or two, but I didn’t really read them fully yet), I did this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl https://api.twilio.com/2010-04-01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;?xml version=&quot;1.0&quot;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;TwilioResponse&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;Version&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;Name&gt;2010-04-01&amp;#x3C;/Name&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;Uri&gt;/2010-04-01&amp;#x3C;/Uri&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;SubresourceUris&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Accounts&gt;/2010-04-01/Accounts&amp;#x3C;/Accounts&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/SubresourceUris&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;/Version&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/TwilioResponse&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I introduced some formatting. Hmm, okay, Accounts. Let’s check this out:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl https://api.twilio.com/2010-04-01/Accounts&amp;#x3C;?xml version=&quot;1.0&quot;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;TwilioResponse&gt;&amp;#x3C;RestException&gt;&amp;#x3C;Status&gt;401&amp;#x3C;/Status&gt;&amp;#x3C;Message&gt;Authenticate&amp;#x3C;/Message&gt;&amp;#x3C;Code&gt;20003&amp;#x3C;/Code&gt;&amp;#x3C;MoreInfo&gt;http://www.twilio.com/docs/errors/20003&amp;#x3C;/MoreInfo&gt;&amp;#x3C;/RestException&gt;&amp;#x3C;/TwilioResponse&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, so I have to be authenticated. If I was, I’d get something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;TwilioResponse&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;Account&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;Sid&gt;ACba8bc05eacf94afdae398e642c9cc32d&amp;#x3C;/Sid&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;FriendlyName&gt;Do you like my friendly name?&amp;#x3C;/FriendlyName&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;Type&gt;Full&amp;#x3C;/Type&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;Status&gt;active&amp;#x3C;/Status&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;DateCreated&gt;Wed, 04 Aug 2010 21:37:41 +0000&amp;#x3C;/DateCreated&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;DateUpdated&gt;Fri, 06 Aug 2010 01:15:02 +0000&amp;#x3C;/DateUpdated&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;AuthToken&gt;redacted&amp;#x3C;/AuthToken&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;Uri&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d&amp;#x3C;/Uri&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;SubresourceUris&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;AvailablePhoneNumbers&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/AvailablePhoneNumbers&amp;#x3C;/AvailablePhoneNumbers&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Calls&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/Calls&amp;#x3C;/Calls&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Conferences&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/Conferences&amp;#x3C;/Conferences&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;IncomingPhoneNumbers&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/IncomingPhoneNumbers&amp;#x3C;/IncomingPhoneNumbers&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Notifications&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/Notifications&amp;#x3C;/Notifications&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;OutgoingCallerIds&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/OutgoingCallerIds&amp;#x3C;/OutgoingCallerIds&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Recordings&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/Recordings&amp;#x3C;/Recordings&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Sandbox&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/Sandbox&amp;#x3C;/Sandbox&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;SMSMessages&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/SMS/Messages&amp;#x3C;/SMSMessages&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      &amp;#x3C;Transcriptions&gt;/2010-04-01/Accounts/ACba8bc05eacf94afdae398e642c9cc32d/Transcriptions&amp;#x3C;/Transcriptions&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    &amp;#x3C;/SubresourceUris&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  &amp;#x3C;/Account&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;/TwilioResponse&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Awesome. I can see my all of the other resources that I can interact with. Other than knowing how to authenticate, I can follow the links from the endpoint, and discover their entire API. Rock. This is the way things are supposed to be.&lt;/p&gt;
&lt;h3 id=&quot;the-bad-1&quot;&gt;The bad&lt;/h3&gt;
&lt;p&gt;This:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl https://api.twilio.com/2010-04-01/Accounts -H &quot;Accept: application/json&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;?xml version=&quot;1.0&quot;?&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;TwilioResponse&gt;&amp;#x3C;RestException&gt;&amp;#x3C;Status&gt;401&amp;#x3C;/Status&gt;&amp;#x3C;Message&gt;Authenticate&amp;#x3C;/Message&gt;&amp;#x3C;Code&gt;20003&amp;#x3C;/Code&gt;&amp;#x3C;MoreInfo&gt;http://www.twilio.com/docs/errors/20003&amp;#x3C;/MoreInfo&gt;&amp;#x3C;/RestException&gt;&amp;#x3C;/TwilioResponse&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Versus this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;$ curl https://api.twilio.com/2010-04-01/Accounts.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&quot;status&quot;:401,&quot;message&quot;:&quot;Authenticate&quot;,&quot;code&quot;:20003,&quot;more_info&quot;:&quot;http:\/\/www.twilio.com\/docs\/errors\/20003&quot;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:/ Returning JSON when your resource ends with ‘.json’ isn’t bad, but not respecting the Accept header, even when you return the right MIME type, is just unfortunate.&lt;/p&gt;
&lt;h2 id=&quot;-and-a-little-announcement&quot;&gt;… and a little Announcement&lt;/h2&gt;
&lt;p&gt;It seems that this is a topic that people are really interested in. Part I of this article was pretty well-received, and I got lots of great email and feedback from people. It was also made pretty clear by &lt;a href=&quot;http://twitter.com/#!/wayneeseguin/status/97733413611638784&quot;&gt;a few&lt;/a&gt; people that they want more content from me on this topic.&lt;/p&gt;
&lt;p&gt;So I decided to write a book about it. You can check out the site for “&lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;Get Some REST&lt;/a&gt;”, and put in your email address. Then you’ll get updated when I start pre-release sales.&lt;/p&gt;
&lt;p&gt;So what’s in “Get Some REST”? It’s going to be a full description of how to build RESTful web applications, from the ground up. Designing your resources, laying out an API, all the details. I’m going to try to keep most of the content language-agnostic, but provide code samples in Rails 3.1, as well.&lt;/p&gt;
&lt;p&gt;I plan on writing a bunch of content, and then releasing the book at half-price in beta. Early adopters will be able to get their two cents in, and I’ll cover things they still have questions on. It’ll be available under a liberal license, in PDF, ePub, all that good stuff.&lt;/p&gt;
&lt;p&gt;I’ve also set up a Twitter account at &lt;a href=&quot;http://twitter.com/hypermediaapis&quot;&gt;@hypermediaapis&lt;/a&gt;. I’ll be tweeting updates about the book, and also other good content related to RESTful design.&lt;/p&gt;</content:encoded></item><item><title>Nobody understands REST or HTTP</title><link>https://steveklabnik.com/writing/nobody-understands-rest-or-http/</link><guid isPermaLink="true">https://steveklabnik.com/writing/nobody-understands-rest-or-http/</guid><description>HI HN , PLEASE READ THIS!!! Since I’ve posted this, I’ve refined a few of my positions on things. Everyone learns and grows, and while I still stand by most of what I said, I specifically don’t agree that versioning the media type is how to properly version APIs. Hypermedia APIs…</description><pubDate>Sun, 03 Jul 2011 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;hi-hn-please-read-this&quot;&gt;&lt;strong&gt;HI &lt;a href=&quot;http://news.ycombinator.com/item?id=3635085&quot;&gt;HN&lt;/a&gt;, PLEASE READ THIS!!!&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Since I’ve posted this, I’ve refined a few of my positions on things. Everyone learns and grows, and while I still stand by most of what I said, I specifically don’t agree that versioning the media type is how to properly version APIs. Hypermedia APIs should not actually use explicit versioning, but I’d rather see a version in the URI with HATEOAS than no HATEOAS and versioned media types. I’ve been meaning to update this post and write more, but alas, my work on &lt;a href=&quot;http://designinghypermediaapis.com/&quot;&gt;Get some REST&lt;/a&gt; has taken priority. I don’t have a HN account, so feel free to &lt;a href=&quot;mailto:steve@steveklabnik.com&quot;&gt;email me&lt;/a&gt; with any thoughts or questions!&lt;/p&gt;
&lt;p&gt;Furthermore, everything in engineering is ALWAYS a trade-off. I primarily wish that more people understood the tools that HTTP provides them with, and made an informed choice, rather than cargo-culting what they’ve seen others do.&lt;/p&gt;
&lt;p&gt;Update: Part II of this post is &lt;a href=&quot;/writing/some-people-understand-rest-and-http/&quot;&gt;here&lt;/a&gt;. Check it out, and there’s an announcement at the end!&lt;/p&gt;
&lt;p&gt;Update: Please note that &lt;a href=&quot;/posts/2012-02-23-rest-is-over&quot;&gt;REST is over. Hypermedia API is the new nomenclature.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The more that I’ve learned about web development, the more that I’ve come to appreciate the thoroughness and thoughtfulness of the authors of the HTTP RFC and Roy Fielding’s dissertation. It seems like the answers to most problems come down to “There’s a section of the spec for that.” Now, obviously, they’re not infallible, and I’m not saying that there’s zero room for improvement. But it really disappoints me when people don’t understand the way that a given issue is supposed to be solved, and so they make up a partial solution that solves their given case but doesn’t jive well with the way that everything else works. There are valid criticisms of the specs, but they have to come from an informed place about what the spec says in the first place.&lt;/p&gt;
&lt;p&gt;Let’s talk about a few cases where either REST or HTTP (which is clearly RESTful in its design) solves a common web development problem.&lt;/p&gt;
&lt;h3 id=&quot;i-need-to-design-my-api&quot;&gt;I need to design my API&lt;/h3&gt;
&lt;p&gt;This one is a bit more general, but the others build off of it, so bear with me.&lt;/p&gt;
&lt;p&gt;The core idea of REST is right there in the name: “Representational State Transfer” It’s about transferring representations of the state… of resources. Okay, so one part isn’t in the name. But still, let’s break this down.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;/h3&gt;
&lt;p&gt;From &lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2_1_1&quot;&gt;Fielding’s dissertation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. “today’s weather in Los Angeles”), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author’s hypertext reference must fit within the definition of a resource. A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When we interact with a RESTful system, we’re interacting with a set of resources. Clients request resources from the server in a variety of ways. But the key thing here is that resources are &lt;em&gt;nouns&lt;/em&gt;. So a RESTful API consists of a set of URIs that map entities in your system to endpoints, and then you use HTTP itself for the verbs. If your URLs have action words in them, you’re doing it wrong. Let’s look at an example of this, from the early days of Rails. When Rails first started messing around with REST, the URLs looked like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/posts/show/1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you use Rails today, you’ll note that the corresponding URL is this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/posts/1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why? Well, it’s because the ‘show’ is unnecessary; you’re performing a GET request, and that demonstrates that you want to show that resource. It doesn’t need to be in the URL.&lt;/p&gt;
&lt;h3 id=&quot;a-digression-about-actions&quot;&gt;A digression about actions&lt;/h3&gt;
&lt;p&gt;Sometimes, you need to perform some sort of action, though. Verbs are useful. So how’s this fit in? Let’s consider the example of transferring money from one Account to another. You might decided to build a URI like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;POST /accounts/1/transfer/500.00/to/2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to transfer $500 from Account 1 to Account 2. But this is wrong! What you really need to do is consider the nouns. You’re not transferring money, you’re creating a Transaction resource:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;POST /transactions HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Host: &amp;#x3C;snip, and all other headers&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;from=1&amp;#x26;to=2&amp;#x26;amount=500.00&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Got it? So then, it returns the URI for your new Transaction:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 201 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Date: Sun, 3 Jul 2011 23:59:59 GMT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Content-Length: 12345&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Location: http://foo.com/transactions/1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&quot;transaction&quot;:{&quot;id&quot;:1,&quot;uri&quot;:&quot;/transactions/1&quot;,&quot;type&quot;:&quot;transfer&quot;}}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whoah, &lt;a href=&quot;http://timelessrepo.com/haters-gonna-hateoas&quot;&gt;HATEOS&lt;/a&gt;! Also, it may or may not be a good idea to return this JSON as the body; the important thing is that we have the Location header which tells us where our new resource is. If we give a client the ID, they might try to construct their own URL, and the URI is a little redundant, since we have one in the Location. Regardless, I’m leaving that JSON there, because that’s the way I typed it first. I’d love to &lt;a href=&quot;mailto:steve@steveklabnik.com&quot;&gt;hear your thoughts on this&lt;/a&gt; if you feel strongly one way or the other.&lt;/p&gt;
&lt;p&gt;EDIT: I’ve since decided that yes, including the URI is a bad idea. The Location header makes much more sense. More on this in Part ii, yet to come.&lt;/p&gt;
&lt;p&gt;Anyway, so now we can GET our Transaction:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /transactions/1 HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Accept: application/json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the response:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;HTTP/1.1 blah blah blah&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{&quot;id&quot;:1,&quot;type&quot;:&quot;transfer&quot;,&quot;status&quot;:&quot;in-progress&quot;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So we know it’s working. We can continue to poll the URI and see when our transaction is finished, or if it failed, or whatever. Easy! But it’s about manipulating those nouns.&lt;/p&gt;
&lt;h3 id=&quot;representations&quot;&gt;Representations&lt;/h3&gt;
&lt;p&gt;You’ll notice a pair of headers in the above HTTP requests and responses: Accept and Content-Type. These describe the different ‘representation’ of any given resource. From &lt;a href=&quot;http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_2_1_2&quot;&gt;Fielding&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components. A representation is a sequence of bytes, plus representation metadata to describe those bytes. Other commonly used but less precise names for a representation include: document, file, and HTTP message entity, instance, or variant.A representation consists of data, metadata describing the data, and, on occasion, metadata to describe the metadata (usually for the purpose of verifying message integrity).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So &lt;code&gt;/accounts/1&lt;/code&gt; represents a resource. But it doesn’t include the form that the resource takes. That’s what these two headers are for.&lt;/p&gt;
&lt;p&gt;This is also why adding &lt;code&gt;.html&lt;/code&gt; to the end of your URLs is kinda silly. If I request &lt;code&gt;/accounts/1.html&lt;/code&gt; with an &lt;code&gt;Accept&lt;/code&gt; header of &lt;code&gt;application/json&lt;/code&gt;, then I’ll get JSON. The &lt;code&gt;Content-Type&lt;/code&gt; header is the server telling us what kind of representation it’s sending back as well. The important thing, though, is that a given resource can have many different representations. Ideally, there should be one unambiguous source of information in a system, and you can get different representations using &lt;code&gt;Accept&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;state-and-transfer&quot;&gt;State and Transfer&lt;/h3&gt;
&lt;p&gt;This is more about the way HTTP is designed, so I’ll just keep this short: Requests are designed to be stateless, and the server holds all of the state for its resources. This is important for caching and a few other things, but it’s sort of out of the scope of this post.&lt;/p&gt;
&lt;p&gt;Okay. With all of that out of the way, let’s talk about some more specific problems that REST/HTTP solve.&lt;/p&gt;
&lt;h3 id=&quot;i-want-my-api-to-be-versioned&quot;&gt;I want my API to be versioned&lt;/h3&gt;
&lt;p&gt;The first thing that people do when they want a versioned API is to shove a /v1/ in the URL. &lt;em&gt;THIS IS BAD!!!!!1&lt;/em&gt;. &lt;code&gt;Accept&lt;/code&gt; solves this problem. What you’re really asking for is “I’d like the version two representation of this resource.” So use accept!&lt;/p&gt;
&lt;p&gt;Here’s an example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GET /accounts/1 HTTP/1.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Accept: application/vnd.steveklabnik-v2+json&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You’ll notice a few things: we have a + in our MIME type, and before it is a bunch of junk that wasn’t there before. It breaks down into three things: &lt;code&gt;vnd&lt;/code&gt;, my name, and &lt;code&gt;v2&lt;/code&gt;. You can guess what v2 means, but what about &lt;code&gt;vnd&lt;/code&gt;. It’s a &lt;a href=&quot;http://tools.ietf.org/html/rfc4288#section-3.2&quot;&gt;Vendor MIME Type&lt;/a&gt;. After all, we don’t really want just any old JSON, we want my specific form of JSON. This lets us still have our one URL to represent our resource, yet version everything appropriately.&lt;/p&gt;
&lt;p&gt;I got a comment from &lt;a href=&quot;http://avdi.org/&quot;&gt;Avdi Grimm&lt;/a&gt; about this, too:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here’s an article you might find interesting: &lt;a href=&quot;http://www.informit.com/articles/article.aspx?p=1566460The&quot;&gt;http://www.informit.com/articles/article.aspx?p=1566460The&lt;/a&gt; author points out that MIMETypes can have parameters, which means you can actually have a mimetype that looks like this:vnd.example-com.foo+json; version=1.0Sadly, Rails does not (yet) understand this format.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;id-like-my-content-to-be-displayed-in-multiple-languages&quot;&gt;I’d like my content to be displayed in multiple languages&lt;/h3&gt;
&lt;p&gt;This is related, but a little different. What about pages in different languages? Again, we have a question of representation, not one of content. /en/whatever is not appropriate here. Turns out, &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-14.4&quot;&gt;there’s a header for that: Accept-Language&lt;/a&gt;. Respect the headers, and everything works out.&lt;/p&gt;
&lt;p&gt;Oh, and I should say this, too: this doesn’t solve the problem of “I’d like to read this article in Spanish, even though I usually browse in English.” Giving your users the option to view your content in different ways is a good thing. Personally, I’d consider this to fall out in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s temporary. Stick this option in the session, and if they have the option set, it trumps the header. You’re still respecting their usual preferences, but allowing them to override it.&lt;/li&gt;
&lt;li&gt;It’s more permanent. Make it some aspect of their account, and it trumps a specific header. Same deal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;id-like-my-content-to-have-a-mobile-view&quot;&gt;I’d like my content to have a mobile view&lt;/h3&gt;
&lt;p&gt;Sounds like I’m beating a dead horse, but again: it’s a representation question. In this case, you’d like to vary the response by the User-Agent: give one that’s mobile-friendly. There’s a whole list of &lt;a href=&quot;http://www.w3.org/TR/mobile-bp/&quot;&gt;mobile best practices&lt;/a&gt; that the w3c recommends, but the short of it is this: the User-Agent should let you know that you’re dealing with a mobile device. For example, here’s the first iPhone UA:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, once detecting you have a mobile User-Agent, you’d give back a mobile version of the site. Hosting it on a subdomain is a minor sin, but really, like I said above, this is really a question of representation, and so having two URLs that point to the same resource is kinda awkward.&lt;/p&gt;
&lt;p&gt;Whatever you do, for the love of users, please don’t detect these headers, then redirect your users to m.whatever.com, at the root. One of my local news websites does this, and it means that every time I try to follow a link from Twitter in my mobile browser, I don’t see their article, I see their homepage. It’s infuriating.&lt;/p&gt;
&lt;h3 id=&quot;id-like-to-hide-some-of-my-content&quot;&gt;I’d like to hide some of my content&lt;/h3&gt;
&lt;p&gt;Every once in a while, you see a story like this: &lt;a href=&quot;http://www.boingboing.net/2010/10/25/local-newspaper-boas.html&quot;&gt;Local paper boasts ultimate passive-agressive paywall policy&lt;/a&gt;. Now, I find paywalls distasteful, but this is not the way to do it. There are technological means to limit content on the web: making users be logged-in to read things, for example.&lt;/p&gt;
&lt;p&gt;When this was discussed on Hacker News, &lt;a href=&quot;http://news.ycombinator.com/item?id=1834075&quot;&gt;here’s&lt;/a&gt; what I had to say:&lt;/p&gt;
&lt;p&gt;nkurz:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I presume if I had an unattended roadside vegetable stand with a cash-box, that I’d be able to prosecute someone who took vegetables without paying, certainly if they also made off with the cash-box. Why is this different on the web? And if a written prohibition has no legal standing, why do so many companies pay lawyers to write click-through “terms of service” agreements?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why is this different on the web?Let’s go through what happens when I visit a web site. I type a URL in my bar, and hit enter. My web browser makes a request via http to a server, and the server inspects the request, determines if I should see the content or not, and returns either a 200 if I am allowed, and a 403 if I’m not. So, by viewing their pages, I’m literally asking permission, and being allowed.It sounds to me like a misconfiguration of their server; it’s not doing what they want it to.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;id-like-to-do-some-crazy-ajax-yet-have-permalinks&quot;&gt;I’d like to do some crazy ajax, yet have permalinks&lt;/h3&gt;
&lt;p&gt;This is an example of where the spec is obviously deficient, and so something had to be done.&lt;/p&gt;
&lt;p&gt;As the web grew, AJAXy ‘web applications’ started to become more and more the norm. And so applications wanted to provide deep-linking capabilities to users, but there’s a problem: they couldn’t manipulate the URL with Javascript without causing a redirect. They &lt;em&gt;could&lt;/em&gt; manipulate the anchor, though. You know, that part after the #. So, Google came up with a convention: &lt;a href=&quot;http://code.google.com/web/ajaxcrawling/docs/getting-started.html&quot;&gt;Ajax Fragments&lt;/a&gt;. This fixed the problem in the short term, but then the spec got fixed in the long term: &lt;a href=&quot;http://dev.w3.org/html5/spec-author-view/history.html&quot;&gt;pushState&lt;/a&gt;. This lets you still provide a nice deep URL to your users, but not have that awkward #!.&lt;/p&gt;
&lt;p&gt;In this case, there was a legitimate technical issue with the spec, and so it’s valid to invent something. But then the standard improved, and so people should stop using #! as HTML5 gains browser support.&lt;/p&gt;
&lt;h3 id=&quot;in-conclusion&quot;&gt;In conclusion&lt;/h3&gt;
&lt;p&gt;Seriously, most of the problems that you’re solving are social, not technical. The web is decades old at this point, most people have considered these kinds of problems in the past. That doesn’t mean that they always have the right answer, but they usually do have an answer, and it’d behoove you to know what it is before you invent something on your own.&lt;/p&gt;</content:encoded></item></channel></rss>