End HTTP abuse

Web access toolkits should make it easier to do the right thing

You'd think that a language with a mere handful of verbs, only two of which are widely spoken, would be easy to learn. Not so in the case of the HTTP, though. After more than a decade, we're still sorting out how and why to use its most common verbs: GET and POST.

This perennial issue recently flared up again when Microsoft's Dare Obasanjo noted that three popular services had got it wrong. Bloglines, Flickr, and del.icio.us all offer APIs that claim to be RESTful -- that is, to conform to the Representational State Transfer principles of HTTP -- yet each violates those principles by allowing GET in some cases where only POST should be allowed.

There are two reasons why a service ought to allow HTTP GET, when it's appropriate to do so. First, the resulting URL remains visible in the browser's address (location) field. That means you can bookmark a request, post it to the Web, or send it to someone in an e-mail. If you've ever wanted to save a search but couldn't, the reason is probably that the form unnecessarily used POST rather than GET.

A second rationale for GET is that various systems along an HTTP pipeline may be able to cache the response.

GET's purpose, however, is only to retrieve information. When you offer a service that updates a resource, you should disallow GET and require clients to use POST. (There are also rarely used HTTP verbs to PUT or DELETE resources, but that's another story.) The reasoning here is twofold: You don't want users to invoke resource-altering requests from hyperlinks. And, such requests aren't cacheable.

Why didn't Bloglines, Flickr, or del.icio.us enforce the POST restriction? I suspect it's because they wanted their APIs to have the broadest possible reach. And from a programmer's perspective, the simplest and easiest HTTP clients are those that use GET.

As an experiment, I sent both GET and POST requests to one of the indicted APIs using four different HTTP client technologies. First up was Curl, the Swiss-army knife of command-line-based URL fetchers. In this case, happily, it was trivial to convert a GET-style request to one that uses POST. I just took the part of the URL that followed the question mark and stuck it after a -d flag. I might have had to look that up, but it's only a small step off the path of least resistance.

The same held true for Python's basic one-line URL fetcher, urllib. In this case I took what followed the URL's question mark and attached it to the optional data argument. Again, just a small extra step.

With Perl, though, I had to take a bigger step. Perl's basic one-line URL fetcher is implemented by the LWP::Simple module. But to switch from GET to POST, I had to construct an LWP::UserAgent object, call its post method, and encode the arguments in a data structure.

Likewise with JavaScript. I could issue a GET request by simply assigning a URL to the location.href object. To issue a POST, though, I had to construct a form or use the nonstandard XMLHttpRequest object.

These aren't huge obstacles. But if all toolkits made POST as accessible as GET -- or as nearly so as possible -- there would be less incentive to misuse GET.

It should be easy to do the right thing.

Copyright © 2005 IDG Communications, Inc.