when to use GET vs PUT, and what should happen if a PUT URI is typed in?

83 Views Asked by At

(This is not really specific to Rails, but I'll use Rails constructs to ask the question).

TL;DR

What should happen when a user types a URI into the address bar that really is a PUT operation and not a GET?

Details

Let's assume we have a web-enabled Gauge that keeps a copy of its most recently read value in a database (for efficiency), but the user can request an update to refresh the cached value. So here's what the routes might look like:

VERB | URI Pattern       | Effect
-----+-------------------+------------------------------------
GET  | /gauge/:id        | show the cached state of gauge #id
PUT  | /gauge/:id/update | update the cached state of gauge #id

I've chosen GET to show the cached state of the gauge, since you can perform any number of GETs and the results will never change. In the terminology of http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html, the GET operation is idempotent. Thus GET /gauge/33 will fetch the cached value of gauge #33.

As best I understand RFC2616, I MUST use a PUT to update the local state, since the state can change at each call: it is not idempotent. Stated another way PUT /gauge/33/update causes a side effect in the database.

Now: Stop me right here if I'm misinterpreting RCF2616 and I'll skulk away quietly.

The question

My question is really kind of simple: what should happen if the user types /gauge/33/update into the address bar of a browser? That presents to the server as GET /gauge/33/update, but there's no route that matches that.

Is it common practice to set up a route that includes both a GET and a PUT for the same URI pattern? That is, I could set up my routing table as:

VERB | URI Pattern       | Effect
-----+-------------------+------------------------------------
GET  | /gauge/:id        | show the cached state of gauge #id
PUT  | /gauge/:id/update | update the cached state of gauge #id
GET  | /gauge/:id/update | perhaps the same as PUT (but see below)

My concern about that approach is that if a user invokes GET /gauge/33/update two (or more) times in a row, a server might decide that -- since GET signals an idempotent operation -- it doesn't actually need to perform the update.

I just being pedantic? Or am I misinterpreting RFC2616?

2

There are 2 best solutions below

0
On

they should get error 405

HTTP/405 wrong method

see: http codes

2
On

That presents to the server as GET /gauge/33/update, but there's no route that matches that.

If there is no route it will just load a 404 error (or a 405 according to Jasen). You can't send a PUT request to a server by typing the address in the address bar within the browser.

When using the rails path methods you would want to send a user to the show action, not the update method. So you would use gauge_path(@gauge) to generate the path, which would result in /gauge/123 (assuming that is the gauge's id in the DB. The only time you would want to do a put would be within a form when updating the gauge, like so:

Which will create a form with the method set as PUT.

Check this out for more information.