in REST

Another REST Anti-Pattern

Here is an addition to the list of anti-patterns that Stefan recently posted. The pattern is to let the client "think" that is using verbs other than GET and POST, but piggyback such requests over GET or POST. This was originally started by the GData folks via the X-HTTP-Method-Override header. Rails came along and baked its version for faking PUT, and DELETE over POST.

Let me start with a Rails example.

<%= link_to "Delete Image", @image, :confirm => "Are you sure?", :method => :delete %>

This is from the Rails API documentation.

Here, the intent is to let the client submit a DELETE request to delete a resource. Given that HTML forms do not support DELETE, Rails generates the following HTML:

<a href="/images/9" onclick="if (confirm('Are you sure?')) { var f = document.createElement('form');
f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;
var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method');
m.setAttribute('value', 'delete'); f.appendChild(m);f.submit(); };return false;">Delete Image</a>

When clicked, this creates an HTML form with method POST, and submits it.

What good is this for? I can’t think of any. As far as HTTP is concerned, it is a regular POST and all the rules for POST apply. The browser is still submitting a POST request. The server-side may think that it is implementing a DELETE, but it is of no consequence as far as the client and HTTP are concerned.

The same is the case with X-HTTP-Method-Override. Patterns like this are misleadingly simple, and completely worthless.

Write a Comment

Comment

12 Comments

  1. Interesting – I see the problems with this approach (e.g. tricking firewalls into letting something through they’d normally forbid), but I don’t agree it’s worthless: it lets the server-side code handle DELETEs issued via e.g. curl, wget or some application client in the same way as those issued from a browser.

  2. So what should a RESTful application, one accessed via browser, do? I’m not talking about the particular example of creating a form for links, but if I have a plain old form to update a resource how should I do it? It would only be an Anti-Pattern if it wasn’t used to overcome limitations on HTML.

  3. True, but that is like RPC where the URI or a header includes the verb used by the server application while the client and the network need to treat it as an HTTP POST. This is not very much different from how WS-Transfer wants to do PUTs and DELETEs. I am just questioning the intent of such features.

    Such approaches can be justified if the intent was to let the same server code handle HTML forms based clients as well as non-forms based clients that can support real PUT and DELETE.

    That may be true for the GData case. But since GData APIs are hosted by Google itself, I would be surprised if their proxies are not configured to support PUTs and DELETEs.

  4. Same with PUT !
    I think its a well understood idea in the Rails community that this is only a pragmatic workaround for limitations the browser in its current form imposes.
    If you are using ActiveResource or any other Http client library you don’t have to do this and could send a put/delete request.

    Now that you have made a strong remark it will help to know what your recommendations are for performing restful actions from within a browser?

  5. I don’t see a problem. POST makes fewer guarantees than PUT or DELETE (to be precise, it makes none), so intermediaries won’t make mistaken assumptions about what conditions hold true after such a request. Sure, by tunnelling other methods over POST, you lose the advantages that the stronger guarantees of those methods confer. But as Roy himself has said, it is well possible to design a perfectly RESTful system with just GET and POST.

    What you are calling an anti-pattern is just suboptimal design. It is certainly not on equal footing with the mistakes than Stefan listed such as GET with side-effects.

  6. Check out ActiveResource (also part of Rails). See the verbs?

    By design Rails accepts all the methods. By design Rails uses these methods when it can.

    If the world switched over to HTML 5 tomorrow, Rails developers would just run gem update rails.

    That’s because the hack is buried in the framework, but your application code is written around verb semantics.

    So it deals with the unfortunate incident that is web browsers. It supports clients that can use HTTP methods properly. And it teaches you to develop code around the uniform interface.

  7. REST, including the :method => :hacks for browsers not supporting all of the “verbs”, has been a huge counterproductive diversion for DHH and many of the Rails folks.

    Nobody seems capable of taking a step back. If they did, they’d realize that (real) end-users don’t give a shit about REST, aside from maybe pretty URLs, which have little to do with it.

    Granted, because so much work went into it, you pretty much need to get on the bandwagon when doing Rails these days. It’ll just make your life easier. And yes, ultimately, that makes web services easier to code.

    My point is, in the 1.? -> 1.2 timeframe, and even today, there were way bigger fish to fry.

    Rails people tend to get distracted by shiny things.

  • Related Content by Tag