GET to do POST’s job

GET and POSTWhen is it okay to use GET links to do a POST’s job? And I’m talking about logged-in users, so web crawlers aren’t an issue.

Normally, of course, you should use the POST method with a form when you’re changing stuff on the server end. But in practice tons of websites use GET for POST-like stuff, so it must work okay.

And you can solve problems like Google Web Accelerator pre-fetching pages if you have a ? in the URL, like voteup?id=42. Question is, are there other web accelerators that pre-fetch indiscriminately?

For example, the voting arrows at Y Combinator Startup News are GET links, and they work fine. What’s more, News.YC’s new JavaScript voting mechanism was implemented by none other than Paul Buchheit. If Gmail’s creator doesn’t mind POST-like GETs, does that make them okay?

The main reason I’m asking is that it’s a real pain to style form buttons to look like links. Cross-browser, at least. And that goes for input type="submit" or button elements.

What we’ve got is an Undo link, much like Gmail’s one, but we want it to work with JavaScript off. It really should be a POST, but we had no end of trouble styling the button as a link. Finally — with a lot of hacks — we styled it okay except for the hover colour in IE6.

Anyone else have experience using GET to do POST’s job in cases like this?

Update: I just found (via this helpful PDF) that the “? in the URL” thing is addressed by the standard. Hmmm, perhaps only for HTTP/1.0 servers.

14 June 2007 by Ben    14 comments

14 comments and pings (oldest first)

Mark Cidade 14 Jun 2007, 02:32 link

Yes, people have gotten away with GETs to change observable state on the server, but the more people do that, the more the distinction between GET and POST is blurred. I don’t like that I can’t trust sending a GET request without having an unintended and undesired impact.

What if you use JavaScript to hide the button (button.style.display=’none’) and insert a JavaScript link (element.childNodes.insert(linkNode)) ?

Greg 14 Jun 2007, 02:46 link

This question was discussed on ask meta filter a while ago: Link

Randy Schmidt 14 Jun 2007, 04:00 link

Check out Rediscovering The Button Element if you want a way to style buttons.

tndal 14 Jun 2007, 04:50 link

Never.

GET should be idempotent. What that means is that multiple successive GETs should leave the state of the server unchanged; a single GET has the same effect as multiple GETs [here we’re assuming that each GET has exactly the same querystring arguments].

An example of a non-idempotent GET would be using GET to increment a page counter.

For more about this topic see the entries (in order):

http://www.google.com/search?q=GET+idempotent

Ramon Leon 14 Jun 2007, 04:59 link

Agreed, Never. Using gets to change state is a no no, plain and simple. It’s not OK.

q 14 Jun 2007, 05:20 link

POST should only EVER be used for 1. sending large amounts of data 2. transient pages. for example, when sending the same data again will result in a different page displayed.

GET should always be favored, especially for persistent pages.

Ideally, sites should treat them exactly the same and support both equally for every request. There is absolutely no difference between them beyond what I mentioned above.

mike 14 Jun 2007, 05:38 link

GET should be idempotent. What that means is that multiple successive GETs should leave the state of the server unchanged;

thats not the definition of idempotent. the HTTP spec says nothing about the “state of the server changing”, only that N>0 gets should behave the same as one GET. so incrementing a counter would be invalid. deleting an item, where subsequent requests do nothing, would still be idempotent, as evidenced by the fact that the spec says that PUT and DELETE are also idempotent. idempotent operations are allowed to have side effects.

the notion that GET shouldn’t make any state changes falls under the category of RESTful behavior, which is a good idea. but you’ll never get the entire world wide web to obey perfect RESTful behavior.

id chalk up GET/POST intermingling into the same bin as using <table> for layout. less than ideal, should be avoided, etc. but only for reasons of “we should agree to do things a certain way”, not any technical reason.

Mark Cidade 14 Jun 2007, 08:49 link

GET, PUT, and DELETE are all idempotent but only GET is considered also SAFE. With put and delete, a resource may be created, modified or destroyed (with subsequent identical requests ignored). With GET, server state can change (e.g., hit counter), but observable state shouldn’t change so that you can hit a cache server and get the same thing as if you got it from the original server.

POST is primarily designed to ADD to a list-type resource, so every request is expected to add something new. It can be a list of comments, deletion requests, or for some other form data processing request with side-effects.

Tyler 14 Jun 2007, 13:05 link

Please do not listen to “q”. He’s giving bad advice and abusing the HTTP spec.

Ben 14 Jun 2007, 13:13 link

Agreed, Tyler — the word “troll” came to mind, but I wasn’t sure.

Thanks, guys, some helpful comments there. Basically, we’ve decided that it’s not a good idea to follow the crowds — even the ones we respect. It’ll only bite us, like it bit 37signals a couple of years back.

So, our verdict is the same as tndal’s and Ramon’s: never use GET for POST-like stuff. And we’ll address the cross-browser styling issues as they come up.

Update: Paul Buchheit’s just responded to all this with a dose of healthy pragmatism. This was more my original thinking, and I agree that the web’s a pretty pragmatic place. But I still think it’d be scary to have some new web accelerator delete my users’ data. Maybe be semi-pragmatic and use GET for non-critical stuff (like upvoting).

Chui 16 Jun 2007, 00:56 link

Here is one good reason to not replace POSTs with GETs:

Cross Site Request Forgery http://www.cgisecurity.com/articles/csrf-faq.shtml

Ben 16 Jun 2007, 01:12 link

That’s a helpful article, thanks Chui. However, as this section notes, POST doesn’t help with CSRF attacks. Well, it makes attacks a tiny bit harder, but you can still get users to POST forms cross-site without any trouble.

See my reddit.com CSRF logout demonstration for an example. Allowing cross-site logout is not exactly a major flaw, but I’m sure there are plenty of sites that allow much worse things to slip through this way.

Ping: microBlog » GET, PO… 29 Mar 2008, 15:15 link

[…] a year ago I wrote a short article asking when it’s okay to use GET to do POST’s job. Since then I’ve learnt a bit about web standards and web pragmatism, but also about the […]

[…] a year ago I wrote a short article asking when it’s okay to use GET to do POST’s job. Since then I’ve learnt a bit about web standards and web pragmatism, but also about the […]