Use the Correct HTTP Method in Your XHRs
The HTTP/1.1 standard includes the following HTTP methods.
GET
HEAD
POST
PUT
DELETE
CONNECT
OPTIONS
TRACE
HTML form
elements only allow the GET
and POST
methods. This is still true even in the HTML5 specification. The HTML5 specification authors temporarily added other methods to the HTML5 specification but later removed them.
Long ago, regular browser GET
requests to load pages and HTML form GET
and POST
requests were the only ways web browsers were communicating with web servers. As a result, servers were implemented to support only the GET
and POST
methods. Send a request using a different HTTP method and you’d be taking your chances.
The Ruby on Rails community hopped on the REST train sometime around 2007 and their evangelism forever changed for the better the way web developers design their server APIs. Interest was high for using the PUT
and DELETE
methods, in particular, so that the four basic CRUD operations could be performed.
- Create =
POST
- Read =
GET
- Update =
PUT
- Delete =
DELETE
It wasn’t so easy to just starting to use the desired HTTP methods.
Progressive enhancements was a theme of the day. Web pages needed to work with JavaScript disabled. If JavaScript was disabled, regular HTML forms needed to work and that meant being limited to only GET
and POST
methods. If your server-side delete API was built to expect the DELETE
method, then there was no way for a JavaScript-disabled browser to send the appropriate delete request. So the server needed to also be ready for a POST
request. We ended up “tunnelling” the HTTP method through a POST
request using a hidden parameter _method
which, if present, the server would use instead of the actual HTTP method of the request. In an address book app, a form to delete a contact might look like the following.
<form action="/contact/537" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="Delete">
</form>
Which would generate the HTTP request.
POST /contact/537 HTTP/1.1
Host: contact.me
_method=DELETE
The above request uses POST
which is not at all what the POST
method is intended to signify. POST
is intended to signify that a new resource is to be created on the server. The opposite of what the request actually does.
If you are building a Web 1.0 site today, you still need to resort to the above hacking.
If you are building a JavaScript-rich, browser-based app then read on.
When JavaScript is enabled, we are able to use an XMLHttpRequest
to send requests to the server. In the case of the delete example above, we can use the DELETE
method directly in our request.
var xhr = new XMLHttpRequest();
xhr.open('DELETE', '/contact/537', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// do something successful
} else {
// handle errors
}
}
};
xhr.send();
Which would generate the HTTP request.
DELETE /contact/537 HTTP/1.1
Host: contact.me
This is the HTTP request we want to send but, as is often the case, the web of 2007 beat our good intentions painfully down into the ground. Sadly the web servers were not implemented to handle the DELETE
method. A developer could update his own web server but had no control over the proxy web servers between the web browser and his own web server. Back to the tunnelling hack...
var xhr = new XMLHttpRequest();
xhr.open('POST', '/contact/537', true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// do something successful
} else {
// handle errors
}
}
};
xhr.send("_method=DELETE");
This results in the same undesirable HTTP request as the HTML form submission example above.
POST /contact/537 HTTP/1.1
Host: contact.me
_method=DELETE
It usually takes a long time for the web to upgrade. It especially takes a long time for users to upgrade their web browsers. It was pleasantly surprising how quickly web servers were upgraded to support more HTTP methods.
Since 2012 or even earlier, I’ve been using the PUT
and DELETE
method directly with XMLHttpRequest
. In 2014, we started using the newer PATCH
method for partially updating a resource on the server. As of 2016, with tens of thousands of users and millions of server requests, we have never had even a single bug report that could be attributed to our direct use of these HTTP methods with XMLHttpRequest
.
If you have been using the HTTP method tunnelling hack with XMLHttpRequest
patiently waiting for the day the web was ready, as far as I know, you can stop the tunnelling without any worry. The web of 2016 is plenty ready and capable.
If you have any experience contradicting this recommendation, please let me know.
Comments
Have something to write? Comment on this article.