
Designing a RESTful Web Application - RyanMcGreal
http://quandyfactory.com/blog/65/designing_a_restful_web_application
======
troels
"This collision between the inclination to regard PUT as creating and POST as
updating is a significant source of confusion about how to well-design a
RESTful system, and deserves more attention."

I like this text for explicitly bringing this problem up.

------
fi0660
Roy would probably replace occurrences of the word RESTful with RPC in the
article:

[http://roy.gbiv.com/untangled/2008/rest-apis-must-be-
hyperte...](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-
driven)

------
danielharan
A nit: "XML is a framework". format != framework

------
mattmcknight
"For example, if you want to add the ability to create an article, it might be
tempting to create a URI called /create_article/. This is wrong, because it
conflates the object (the resource) and the action (creation)."

So what URL do I use if I want to search articles? What if I want to approve
articles? The simple CRUD perspective has fallen apart for me pretty quickly
in practice- I need more than 6 verbs (adding HTTP OPTIONS and HEAD in there).
I think HATEOAS is a pretty good approach, but there still seems to be a lot
of noun-ification going on in RESTful apps just to stick with the style. (e.g,
PUT //article/1234/approval used when disapproving an article)

~~~
carpo
I've always thought that the URL to use when searching articles is the same
you would use when retrieving a collection of articles, just with the search
terms or filters included as parameters, ie, /articles?q=terms

Approving articles could be as simple as posting TRUE to the "approved"
attribute of an article, ie, /articles/1234/approved

You just need to make sure that every resource that can be modified or
retrieved has a URL.

~~~
jamesbritt
Or treat search as a first-class resource.

~~~
RyanMcGreal
I wonder if it makes more sense to treat search as a first class _method_ ,
i.e. issue an HTTP SEARCH request against a resource.

~~~
DougWebb
That could be done; WebDAV introduced several new methods to HTTP. The
drawback is that your clients lose the ability to use standard HTTP libraries
to talk to your service because you're using a non-standard set of methods.
The 'Uniform' in URI and URL doesn't just apply to the resource identifiers;
in a RESTful system the methods and representations both need to be uniform as
well. That allows general-purpose clients to be able to interact with the
service, and that was what made the web take off when earlier FTP and Gopher
systems did not.

------
BerislavLopac
It's fascinating how we're just starting to use HTTP as it was designed,
nearly twenty years later... :)

------
DougWebb
Regarding response data formats, xhtml has the advantage of being both html (a
format browsers know how to handle) and xml (a format that is well structured
and parsable.)

Semantically, xhtml can represent all of the same data structures/types as
JSON: lists are UL elements, dictionaries are OL elements, numbers, strings,
and booleans are really just strings in both, objects are really just
dictionaries, and nulls in xhtml can be a special string as in JSON or an
empty element.

In both cases, the client has to either already know about the data structure
and how to navigate it, or can treat it generically. XHTML has an advantage
here; every data item can be labeled with an id or class attribute to make it
easier to find. You can't do that in JSON unless everything is a dictionary
value.

For methods, browsers support GET and POST, and they can simulate PUT with
upload controls. For DELETE, the common approach is to use POST with
_method=DELETE as a parameter. That's easy to adjust in your service as the
request comes in so most of your service doesn't have to know about it.

Browsers are also pretty good about sending other headers, particularly the
ones that have to do with caching. That'll force you to deal with them, which
is a good thing.

Ideally, you'll want to just generate a data structure internally, and use the
Accept request header to determine whether to send a text/json or text/html
response. That way clients that want JSON can ask for and get it, while
generic clients (eg: browsers) will get something they can handle. You'll also
be generating the xhtml programatically, which will help to keep it uniform
and predictably structured.

~~~
rimantas

      >xhtml has the advantage of being both html
      >(a format browsers know how to handle) and
      >xml (a format that is well structured and parsable.)
    

And where is the advantage in that over JSON? It's just a Javascript object
and browsers know very well how to handle it. That's the point.

    
    
      >Semantically, xhtml can represent all of
      >the same data structures/types as JSON
    

XHTML has HTML semantics, i.e. it's intended to be used to mark the _structure
of the text_. It has no advantage for a general purpose data exchange.

    
    
      >dictionaries are OL elements
    

Nope. Or did you think about DL/DT/DD? Still nope.

    
    
      >numbers, strings, and booleans are really just strings in both
    

Nope. In JSON only strings are strings. Numbers, booleans and null are
Javascript numbers, booleans and null.

    
    
      >objects are really just dictionaries
    

Objects are objects. Entire JSON response is an object, you can assign it to
variable and use straight away.

    
    
      >and nulls in xhtml can be a special string as in JSON or an empty element.
    

As I said, nulls in JSON are Javascript nulls, not "some special string".

    
    
      >In both cases, the client has to either already know about
      >the data structure and how to navigate it, or can treat it
      >generically. XHTML has an advantage here; every data item
      >can be labeled with an id or class attribute to make it
      >easier to find. You can't do that in JSON unless everything
      >is a dictionary value.
    

Uhm. If we are talking about data in key-value then JSON has a _huge_
advantage there. Not only you _can_ do it in JSON, but you do exactly that and
with very little overhead—that's exactly what makes JSON so attractive and
popular.

var article = {"title":"Adventures in JSON land", "authors":[{"name":"Jane
Doe"}], "published":false, "tags":["JSON", "Javascript", "data format"]}.

That's it. Want to access your data? It's right there:

    
    
      article.title -> "Adventures in JSON land"
      article.authors[0].name -> "Jane Doe"
      article.tags.length -> 3
    

Now do the same in XHTML and you will have much better understanding what
advantages of JSON are.

~~~
DougWebb
The advantage of XHTML over JSON is that you don't need a specialized client
to work with it. You can use the browser, which is a general-purpose client,
and that will benefit you hugely during development and testing. There's a
whole world of tools for testing web pages, both browser-based and library-
based, and all of that can be used with your service if you use xhtml
representations.

    
    
      >Nope. In JSON only strings are strings. Numbers, booleans and null are Javascript numbers, booleans and null.
    

I assume you've looked at a JSON message. On the wire, it's all strings. Null
is represented by the four characters n, u, l, and l. It's the message parser
that turns that into a real null, and an XML parser can do that too.

I'm not saying that JSON doesn't have an advantage when your client language
is javascript, but even in javascript the best-practice is to use a real
parser for JSON rather than just eval. If you've got to use a real parser
anyway, you can also use the xml parser that's built into the browser.
Combined with a library like jQuery which gives you xpath-like retrieval it's
pretty easy:

    
    
        <div id="article">
            <dl>
                <dt>Title: </dt><dd id="title">Adventures in JSON land</dd>
                <dt>Authors: </dt><dd id="authors">
                    <ul>
                        <li class="name">Jane Doe</li>
                    </ul>
                </dd>
                <dt>Published:</dt><dd id="published">false</dd>
                <dt>Tags:</dt><dd id="tags">
                    <ul>
                        <li class="tag">JSON</li>
                        <li class="tag">Javascript</li>
                        <li class="tag">data format</li>
                    </ul>
                </dd>
           </dl>
        </div>
    

Retrieve that into msg, and then:

    
    
        $("#title", msg) -> "Adventures in JSON land"
        $("#authors:first .name", msg) -> "Jane Doe"
        $("#tags li", msg).length -> 3
    

To be fair, an extra step is needed for turning true, false, and null into
real boolean and null values. That's a solvable problem, and so is turning the
xhtml into a javascript object just like the JSON parser does if that's what
you want.

Also, notice that I recommended the service be able to produce BOTH json and
xhtml. Special-purpose clients can use the json representation, and general-
purpose clients can use the xhtml representation. That gives you the best of
both worlds, and the code that produces either/or from an internal data
structure is easy and small so it's not likely to introduce inconsistencies
between the two representations.

------
rmk
I'm thinking of forwarding this link to my boss, so that he can get a quick
tour of REST :) Thanks!

------
jsharpe
another nit: GET requests _are_ idempotent, but that's a necessary, not
sufficient, condition. You should just say they have no side effects.

~~~
_sh
And another: PUT is conceptually closer to 'replace' than 'update'. To me,
'update' implies a delta, as in SQL.

------
RyanMcGreal
Thanks to danielharan, jsharpe and _sh for helpfully picking nits with the
entry. I've updated it to reflect your observations.

------
nkohari
The author seems to get confused himself about PUT vs. POST. At one point he
says POST is used to create resources, and at another point he says PUT
matches up roughly with SQL's INSERT (ignoring idempotence).

~~~
RyanMcGreal
> It's tempting to assume that the HTTP verbs line up nicely with the SQL CRUD
> verbs: [...] They're superficially similar but they're not identical, and
> treating them as such leads to this kind of gotcha.

