0

(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?

Community
  • 1
  • 1
fearless_fool
  • 33,645
  • 23
  • 135
  • 217

2 Answers2

0

they should get error 405

HTTP/405 wrong method

see: http codes

Jasen
  • 11,837
  • 2
  • 30
  • 48
0

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.

Ken Stipek
  • 1,512
  • 8
  • 12
  • I apologize -- I wasn't clear in my question. I know it DOES load a 40x error. I was asking, from a UX perspective, what SHOULD happen. Raising a 40x error isn't particularly helpful, so is it appropriate to add a GET method so it does work? But then am I violating RCF2616 (since it had side effects on the DB)? – fearless_fool Dec 07 '14 at 15:26
  • Raising a 40x error is the correct thing to do. There shouldn't be any links within the application to that path, so if someone reaches it, it is unexpected behavior that should result in some type of error. In this case a 40x error. – Ken Stipek Dec 07 '14 at 20:36