Faking HTTP verbs

Remember how we said that in an HTML form we can specify the HTTP verb that is supposed to be used for making the request like so:

<form action="/monstas" method="post">
  ...
</form>

This makes the form POST to /monstas, instead of the default GET.

Now, it’s probably fair to say that every sane person in the world would expect that it is also possible to make that a PUT, or DELETE request. Like so:

<form action="/monstas" method="put">
  ...
</form>

Except that … it’s not. Today’s browsers still do not allow sending HTTP requests using any other verb than GET and POST.

The reasons for why that still is the case in 2015 are either fascinating or sad, depending how you look at it [1] But for now we’ll just need to accept that, and work around it.

Sinatra (as well as Rails, and other frameworks) therefore support “faking” requests to look as if they were PUT or DELETE requests on the application side, even though in reality they’re all POST requests.

This works by adding a hidden form input tag to the form, like so:

<input name="_method" type="hidden" value="put" />

A hidden input tag is just that, it is hidden, meaning that it is not displayed to the user. However, it is there, and it will be sent to the application as part of the request just like any other input tag.

In order to make this work we also need to tell Sinatra that we want this kind of behaviour. Developers say we need to “opt in” to it. Like so:

use Rack::MethodOverride

Now, whenever Sinatra receives a POST request that has a parameter with the name _method it will treat this request as if it was a request with the HTTP method (verb) given by this parameter. This way one can add data to the form that isn’t relevant to the user, but relevant to the application.

Sinatra will treat any POST request that has the parameter _method set to put as a PUT HTTP request: it will use a route that was defined with put. Likewise, it will treat a POST request that has the paramter set to delete as a DELETE HTTP request, and use the respective route.

This way we can write our application code as if browsers support sending forms as PUT or DELETE requests, even though they don’t. The only thing we need to do is add that little hidden input form field.

The parameter name _method, with an underscore in front, has been chosen to indicate that it’s a “private” concern: it is something that Sinatra manages for us. Also, by choosing an unusual name like this it won’t clash with our own form input fields, in case we ever need to add a form field named method, e.g. for, maybe, a payment method, or a shipping method, or whatever else.

Footnotes

[1] You can read more about this, for example, here.