Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Rails' REST implementation be said to be REST at all?

So, I'm learning Ruby on Rails. I get the fundamentals of the RESTful approach to application architecture, but I haven't yet built a RESTful application completely.

In a traditional web application, idempotent requests (which don't change any state) are made via HTTP's GET method and all non-idempotent requests are typically made via the POST method. For the application to distinguish between the different actions a POST request might be triggering, there's usually a hidden field in the form that gets included with the POST request, like action=delete or action=add_to_foo_file. This is a fairly simple architecture and is pretty common today, but the REST approach steers us away from this and suggests that this "let's POST everything!" design is considered harmful.

Instead, a RESTful architecture has us manipulating resources via the URIs which uniquely identify them (nouns) and the HTTP request methods (verbs), instead of determining what action to take based on a separate field in the request:

GET    => show the resource
PUT    => update the resource
POST   => create a new resource
DELETE => destroy the resource

So now we come to Ruby on Rails. In Rails, PUT and DELETE are implemented by JavaScript, which changes your links into forms with a hidden field called _method. The form is received from the browser via POST, and then Rails looks for this field and decides whether to route the request to the PUT or DELETE methods of the controller.

Wait, what? That sounds suspiciously like -- even exactly like -- the behavior of a traditional web application, which receives all state-changing requests via POST and inspects specific fields to decide whether to destroy or modify a record.

So how can Rails' approach be said to be RESTful at all, since under the hood, it is just a re-implementation of the "let's POST everything" approach which REST specifically attempts to move away from?

And further, doesn't this approach prevent my Rails app from ever degrading gracefully for people with JS turned off in the browser?

like image 822
Jazz Avatar asked Oct 31 '25 02:10

Jazz


1 Answers

What makes a system RESTful or not isn't so much the verb it uses, but the fact the interactions are driven by the hypermedia (in this case, this includes code-on-demand JavaScript).

The GET/PUT/POST/DELETE mapping you're quoting works fine for CRUD operations, but isn't necessarily appropriate for everything (and isn't necessarily supported by all browsers). This is a reasonable rule of thumb to design a RESTful system, but it's neither sufficient nor necessary. (It's in the same category of ideas as what people insist on when they want "RESTful" URIs: there's no such thing.)

Part of this comes under influence of books like RESTful Web Services. It's a good book, but it came out at a time where WS-*/SOAP was predominant, and where everything was tunnelled through POST. A reaction to SOAP was to make people aware that there were other HTTP verbs they could use.

For REST, what really matters in particular is to respect the notions behind the URI concept, the semantics of each HTTP verb (no side-effects, idempotent requests, ..., where appropriate and if you're using HTTP) and the HATEOS principle. It's an architectural style, don't stress too much about what POST/PUT/DELETE the JavaScript does underneath.

You should certainly read these:

  • REST APIs must be hypertext-driven
  • It is okay to use POST

EDIT: (Following comments)

What I should have said was this: If most frameworks turn DELETE http://server.tld/resource/1 into POST http://server.tld/resource/1?_method=DELETE, then what's the advantage of that approach over just using POST http://server.tld/resource/1?my_method=delete in the first place?

  • It makes the overall goal a little bit cleaner/clearer, in terms of API design. REST frameworks can ultimately only be as RESTful as one uses them, since REST is an architectural style, not a protocol or an implementation.
  • In addition, strictly speaking, the URI includes the query component, so http://server.tld/resource/1 and http://server.tld/resource/1?my_method=DELETE could identify different resources in principle (although that wouldn't be a good design choice).
  • It's good for the framework to be able to expose DELETE/PUT as such directly, but have a fallback solution via POST for the clients that don't support it.

    The reason for this is that clients that do support DELETE/PUT will be able to make use of them, and make assumptions about their usage. It's not so much of a problem for the client to treat a request as non-idempotent even if it was idempotent in principle as the opposite. If the client thinks it can send at most 1 request (non-idempotent) when it could have sent N+1 of the requests, this doesn't cause major problems; if the client thinks it can send N+1 times the same request for something that shouldn't be idempotent, this can cause quite a lot of problems. Emulating PUT through POST is OK, you're just not making the most of PUT, emulating POST through PUT would be problematic.

like image 192
Bruno Avatar answered Nov 01 '25 16:11

Bruno



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!