
You know how HTTP GET requests are meant to be idempotent? - mpweiher
https://twitter.com/rombulow/status/990684453734203392
======
wpearse
Hello! Long-time lurker, and guilty dev behind the garage door. You can see
the (broken) code I wrote here:

[https://github.com/wpearse/wemos-d1-garage-door-
wifi](https://github.com/wpearse/wemos-d1-garage-door-wifi)

I'll get around to fixing it later this week.

Also, an apology: I should have used "side-effect-free" instead of
"idempotent" in my tweets.

~~~
inopinatus
> I should have used "side-effect-free" instead of "idempotent" in my tweets

The HTTP term is "safe method". Although you weren't even wrong because
section 4.2.2 of RFC7231 (i.e. HTTP) defines all safe methods, including GET,
as idempotent.

I think they use this language because nothing is truly side-effect free. In
fact GETs _can_ have side-effects, the most obvious of which is writing the
fact of it to a logfile, and that's the most harmless side-effect of all,
right until you run out of disk space.

Being a language arse I think the high precision descriptor is actually
_nullipotent_.
[https://en.wiktionary.org/wiki/nullipotent](https://en.wiktionary.org/wiki/nullipotent)
but I'd never say it out loud.

~~~
cmenge
'Side-effect free' means that doing it once, twice or n >= 3 times (with same
parameters) yields the same result, i.e. what it returns doesn't depend on any
remote state that is _altered by the call itself_.

However, an idempotent HTTP call is certainly not a pure function which some
people seem to be mixing up. Pure functions don't work with I/O.

REST is bit more specific and explicitly requires GET to be nullipotent which
really means "effect free" \- it just reads and doesn't alter the state on the
remote system at all.

Side-effects like log files, rate-limiting, etc. will always exist, but they
do belong to a different 'layer', so to speak. That is, these should be
_unobservable_ side-effects (also think about minuscule effects on the power
grid, the fact that a request might write something to an ARP-cache, etc. -
they all happen at different layers, so the quantum world state keeps
changing, but that's not what this is about). Whether an X-Request-Count
header violates the requirements or not depends on interpretation. From the
garage door perspective, I wouldn't care...

~~~
kiriakasis
> Pure functions don't work with I/O.

there is a comment above that argue this point in better details.

[https://news.ycombinator.com/item?id=16966046](https://news.ycombinator.com/item?id=16966046)

Basically it depends on the many nuances you have on "pure", "functions" and
"idempotent"

~~~
inopinatus
When discussing HTTP behaviours I think it’s easiest to stick to the
definitions of these terms given in the HTTP standard. Anything else is
fruitless bikeshedding.

------
beejiu
When I recently added 'click to unsubscribe' functionality to my emails, the
URL got wrote out into some logs. Those logs got written to a Slack channel
and Slack loves to click any link it sees. Oh, and it doesn't respect
robots.txt.

But all I saw was every member of my list clicking 'unsubscribe'. It took a
good hour to figure out exactly what was going on.

Idempotence is not the problem here, by the way. That just means calling the
method twice has the same effect. But GET should have no side-effect, in an
ideal world. Of course, in the case of unsubscribe links, it needs to have a
side-effect to comply with the law.

~~~
bjackman
Aren't you allowed to have your "click to unsubscribe" button lead to a page
with a button that does a POST that actually unsubscribes? I feel like I've
seen that approach in use.

~~~
criddell
Don't make your users jump through hoops to unsubscribe. That seems like a
typical dark pattern to me.

~~~
mysterydip
Having a single confirmation step to prevent "oops" clicks doesn't seem like a
dark pattern to me.

~~~
icebraining
Confirmation steps should only be used if the action can't be easily undone.

~~~
jimktrains2
And when a user receives an email saying they've been unsubscribed because an
automated system prefetched the link, they won't be concerned or worried or
confused at all. (Especially when this happens _every time_.

~~~
tedunangst
And then the automated system clicks the undo link... Problem solved!

~~~
simcop2387
Which fires off a new email thanking them for re-subscribing.

Soon your inbox is full.

------
DCoder
Many years ago, I was asked to look at why all the content had vanished from a
site (not built by me). After digging in a bit, I found that:

1) the original developer's idea of handling an unauthorized /admin request
was just to set a redirect header and _continue processing the current
request_ .

2) the /admin page had a grid of all the content on the site, with handy
'Delete' links that ran over GET without confirmation.

You can probably guess where this is going – some search bot hit the overview
page, ignored the redirect header, saw the content, and dutifully crawled
every single link on it…

~~~
greglindahl
Was it blekko? We had a website owner email us about that issue when blekko's
ScoutJet crawler was new... although I don't recall the bit about ignored
redirect headers.

~~~
saalweachter
I'm pretty sure everyone with a crawler has hit this sort of problem before.
The first startup I was at did with someone's wiki that had "delete" links
everywhere with no auth.

~~~
greglindahl
Now that I've hit it once, I watch out for websites with this problem. I was
surprised to notice that a Fortune50 tech company's internal employee-
personal-webpages-maker-thingie had that issue. And then a week later they
asked me if I could crawl their internal web. Uh, no, who knows what other
internal systems had that problem?

------
groestl
Idempotency might be necessary for GET calls, but it's not sufficient. Imagine
he had two separate GET calls (opened/closed): the author would still have the
same problem. Browsers assume GET to be safe (non-mutating), and safety
implies idempotency.

~~~
onion2k
Exactly. A 'toggle' should really be implemented as a PATCH request, or maybe
a PUT if there's no data other than the door state.

~~~
hardwaresofton
At the risk of being overly pedantic/piling on -- this is what bad REST-ful
API design looks like in practice.

When you talk to your teammates about the semantics of these verbs and someone
just says "oh a GET is fine" and the team agrees but you don't and you can't
say it so you don't become "that guy" it's time to find a new engineering org
to be a part of.

On the topic of PATCH, check out JSON merge patches (application/merge-
patch+json):

[https://tools.ietf.org/html/rfc7386](https://tools.ietf.org/html/rfc7386)

~~~
Senderman
I hope this doesn't come across as mean-spirited, but I'm really struck by the
middle part of your comment, even though I think it was meant as a throwaway
remark.

It sounds like you're advocating leaving an organisation instead of speaking
up when a mistake is being made? In the scenario you described, the "a GET is
fine" person is unfamiliar with the protocol they're writing for (HTTP), and
so is every person who agreed. Leaving instead of speaking up seems pretty
drastic.

~~~
hardwaresofton
Totally valid question -- it was indeed a throwaway remark but is pretty
bitter in tone now that I think about it.

To delve into what I was thinking a little bit I think it came off so bitter
because I've been in too many orgs where group-thinking squashed dissenting
possibly-correct opinions, where half the room is wondering "this seems too
complex, why are we doing this" but everyone goes with it. Reading through the
twitter comments had a bunch of people were trying to gloss over the misuse
and it might have triggered me.

The more reasonable response is definitely to articulate and explain why a GET
is _NOT_ fine in that case so everyone learns, but once this starts happening
a lot I mark it as a red flag in my head -- it's either a culture clash or I'm
too close to being the most experienced in the room (in that specific area),
and that means there are less people to learn from and staying for too long
might lead to stagnating. The "leave the org" bit is hyperbole, but I worry
about this kind of thing if I experience it.

In the end though, it was meant to be a humorous post so the remark is
overblown.

------
tialaramex
This stuff is also why you should be afraid of any libraries/ frameworks/
tooling that says it's going to automatically offer TLS 1.3's "Zero round
trip" (0RTT) feature for code as opposed to trivial stuff like resource
downloads.

Normally, TLS ensures you can't replay somebody else's conversations. So even
if I know Barry, who is authorised to toggle the door, just sent a "toggle the
door" command, if I try playing it back that won't work, the setup will be
different each connection and I can't respond.

But for 0RTT there is no setup - there can't be, no time to do it, and so if I
replay Barry's "toggle the door" it would work.

The specification is very clear that the right thing here will be to never
allow 0RTT for such features. But the moment that's hidden behind some library
API you can bet _somebody_ is going to screw up badly. Alas our industry
doesn't exactly have a "safety first" mentality.

------
baddox
I’m more surprised that the Safari new tab window makes GET requests to every
“favorite” URL, which I gather is what was happening.

~~~
jedberg
It's updating the thumbnail screenshots. This only happens if you have the
Safari "blank page" be your favorites instead of either your "home page" or a
truly blank page.

~~~
josteink
> if you have the Safari "blank page" be your favorites instead of either your
> "home page" or a truly blank page.

Yay for modern user friendly applications making simple words like blank
completely meaningless and ambiguous.

~~~
Senderman
The commenter may have called it a "blank page", but Safari doesn't; it just
labels the setting as "New tabs open with...", with "Empty page" being one of
the choices.

------
cottsak
The intersection of full-stack web devs from the commercial line-of-business
world; and hardware/embedded hackers brings a lot of room for accidents IMO.
I'm not saying any one of these groups are bad or inept. I'm in the former and
completely accept that I'm new to embedded programming. It seems kool and I
wanna learn about it. But I can also see the flip side where a hardware hacker
sees query strings for toggling an output as a perfectly reasonable interface.
Do we expect the embedded guys to grok HTTP/REST? The web-dev would be like
"no, no, that has to be POST or PUT". But these things are going to happen. We
don't yet have a large pool of experts across both fields.

It's no surprise the level of compromise and breach when you intersect what
were pretty distinct skillsets and dump them in the mixing bowl together.
That's what this IoT thing is like - it's a bunch of household and industrial
chemicals all poured into the one container. It's not going to be very safe.

~~~
JimDabell
> Do we expect the embedded guys to grok HTTP/REST?

REST is irrelevant to this; HTTP alone covers the reason why this is bad. So
ultimately, the question is: "Do we expect somebody designing an HTTP API to
understand HTTP?" I think that's a reasonable expectation. If your embedded
guys don't understand HTTP, then get somebody who does understand HTTP to
design the API. They don't need embedded experience to do so, they aren't
implementing it, just designing it. This isn't a difficult cross-functional
intersection, you just don't assign tasks to people who aren't qualified to
carry them out.

------
astura
This is pretty much the classic newbie web developer mistake, heard many
stories about people making it when they first start. I've also seen people
fuck up in the opposite way, using POST when they should use GET and having
unexpected behavior. Though not usually as "funny" as the classic "using GET
instead of POST" errors are.

This concept of HTTP request methods really should be explained to new
developers in a more accessible way, with examples of mistakes. It might not
be intuitive at first or they might not think it's important as it is.

"Idempotence" isn't really the problem here, nor "should" GET requests be
idempotent, think kittenwar.com or stumbleupon, the problem here is GET is
reserved for retrieving (getting!) data, it shouldn't modify data. (Other than
access information.)

~~~
phab
GET requests are specified[0] to be idempotent:

    
    
      > Methods can also have the property of "idempotence" in that (aside from
      > error or expiration issues) the side-effects of N > 0 identical
      > requests is the same as for a single request. The methods GET, HEAD,
      > PUT and DELETE share this property.
    

[0]
[https://tools.ietf.org/html/rfc2616#section-9.1.2](https://tools.ietf.org/html/rfc2616#section-9.1.2)

edit: formatting

~~~
astura
Looks like the RFC talks about idempotence from a "side effect" perspective
where I was talking about it from an "output" perspective (the generated
HTML).

I agree with the RFC and I mistook what the person meant

------
tlrobinson
I saw “GET request” “idempotent” and “WiFi control garage doors” and
immediately inferred the punchline.

At least it was his own devices and not Googlebot or something, I guess.

------
wwweston
Perhaps we need a specific nomenclature for this sort of case: oddempotent!

After all, you get the same state if you do it 3,5,7,9,etc times as if you do
it once, right? ;)

~~~
hashmush
That would be an involution!

[https://en.wikipedia.org/wiki/Involution_(mathematics)](https://en.wikipedia.org/wiki/Involution_\(mathematics\))

------
myth_buster
Readable format.

[https://threadreaderapp.com/thread/990684453734203392.html](https://threadreaderapp.com/thread/990684453734203392.html)

------
baddox
The first time I clicked the link, Twitter said I was rate limited. I thought
that was the joke.

------
MrMid
Well, a while ago I saw this code (on my own project!):
window.open("?controller=users&action=changePassword&name=" \+ user_name +
"&password=" \+ password)

I was horrified, glad it isn't live yet, and I fixed it immediately. But I'm
still wondering whether I was so sleep-deprived or drunk when I wrote this.
It's over SSL, so it should not be that big deal, but still, GET shouldn't be
used for such things.

~~~
dogma1138
Well you don’t seem to validate the existing password prior to authorizing the
change.

Good CSRF protection on GET requests is also near impossible to implement as
GET is intended to be a “safe” request as in a request that does not modify a
state but this isn’t something that is actually practiced.

~~~
MrMid
Actually, I do. This is not a form for user to change his own password, rather
a administrators form to change another user's form. And for such actions the
administrators identity and privileges are checked. But I understand your
reasoning and thank you for pointing it out.

And yeah, I try to use GET only for safe requests, but I should be more
careful.

------
micimize
This comment thread has really put me in a good mood. These stories have so
much pedagogical value: • The grammars we engineer have important semantic
value • understanding and adhering to them is important, and hard • relying on
others to adhere to them is dangerous, and hard to avoid • "experts" make
mistakes in both areas constantly

I genuinely love seeing this kind of lively discussion, because these
seemingly "trivial details" matter, a lot. The Three Mile Island accident was
more or less caused by "message sent" being conflated with "state changed" at
the UI level, directly leading to a nuclear meltdown. They basically had a
system with the equivalent design of GET /open and /close that assumed success
for both
[https://en.wikipedia.org/wiki/Three_Mile_Island_accident#Con...](https://en.wikipedia.org/wiki/Three_Mile_Island_accident#Confusion_over_valve_status)

------
diminoten
This is a little bit (not a lot though) like the /reset.htm endpoint on some
Arris Surfboard modems.

[https://news.softpedia.com/news/csrf-bug-in-
over-135-million...](https://news.softpedia.com/news/csrf-bug-in-
over-135-million-arris-modems-lets-anyone-factory-reset-the-
devices-502672.shtml)

------
AnIdiotOnTheNet
Two thoughts:

1) Twitter is a terrible medium for anything, let alone posts longer than a
sentence.

2) The level of over-engineering tech people readily engage in without a
second thought is truly mind boggling.

~~~
a13n
1) Market disagrees with you strongly, hence hundreds of millions of people
using it regularly.

2) He's just having fun, working on a side project that's useful to him, and
learning. Nothing wrong with any of that.

Why so negative?

~~~
AnIdiotOnTheNet
1) Popularity is rarely an indicator of quality.

2) That doesn't mean it isn't over-engineering.

~~~
always_good
If actually being used by people isn't part of your criteria for a good
medium, then I'm not sure it's very useful.

------
joesb
> "I threw the code together in minutes and was too lazy to spend another
> couple minutes figuring out POST."

So it's not the vendor's problem then. They provide you with two ways to make
a request. You have a choice to do it right, you didn't.

~~~
acdha
The device should not support GET at all for this. It opens up a number of
attacks and there’s no good reason to support it.

------
NewEntryHN
GET requests aren't supposed to be idempotent. They're not supposed to change
state in a first place.

~~~
dragonwriter
> GET requests aren't supposed to be idempotent.

RFC 7231 disagrees.

> They're not supposed to change state in a first place.

Well, yeah, GET is supposed to be safe, but all safe methods are also
idempotent.

~~~
CoolAndComposed
Just because a server announces HTTP/1.1 doesn't mean it conforms to that
specific RFC.

~~~
dragonwriter
That non-RFC-compliant implementations of HTTP exist irrelevant to what
properties HTTP methods are _supposed_ to have, which is the issue under
discussion.

~~~
CoolAndComposed
It is compliant to an RFC, just not a specific RFC. That's part of the issue,
that's simply taken for granted because of ideology.

------
shocks
My desk height is set with a GET.

I was going to fix it, but considering how hilarious this is I might not.

~~~
andai
Your desk runs a web server? I need to step up my game...

~~~
shocks
Yeah, it's a sit/stand Linak desk.

I hooked up an ESP32, 2 channel relay (up/down control), and distance sensor
(to detect height). Pushes height to graphite and position is settable
remotely. :)

~~~
pbhjpbhj
It's been an hour, is your desk oscillating yet?

~~~
shocks
No, but I had to implement a lock feature because my colleagues apparently
cannot be trusted...

------
didibus
Primary effect - An effect on the input arguments, who's effect is captured in
the output.

Side effect - An effect on state that was not passed in as input arguments,
who's effect may or may not be captured on the output.

Side effect free - Also known as pure, means the function only has a primary
effect. Thus it only effects the input in a way that the output captures.

Idempotent - Applying a function to itself results in the same effects.
Applies to both primary and side effects.

Where things get weird, is that there's also the following:

\- An effect on implicit input state, which did not come from input arguments,
who's effect is captured on the output. This would be like a HTTP GET. Or any
query on a DB where the DB is an implicit input.

\- An effect who's effect is captured on implicit output state, either by
having its effect captured on an input (like a modification to a pointed
object), or captured on output not returned by the function (like print to
screen). This would be like a HTTP POST.

And now if you look at all these, there's an easy permutations of them. So you
can build a table like so:

    
    
      Input | Output | Idempotent
      Arguments | Return Value | Yes
      Arguments | Return Value | No
      Arguments | Outside State | Yes
      Arguments | Outside State | No
      Arguments | Arguments | Yes
      Arguments | Arguments | No
      Outside State | Return Value | Yes
      Outside State | Return Value | No
      Outside State | Arguments | Yes
      Outside State | Arguments | No
      Outside State | Outside State | Yes
      Outside State | Outside State | No
    

All these combinations are possible. That's why it can be really tricky.

------
tudorconstantin
Also, having your garage door opened with unauthorized requests seems like
looking for trouble

~~~
wpearse
Yeah, did wonder about that. My thinking at the time was that the device was
on the local WiFi network, not exposed to the internet, and there would be
easier ways of getting into the garage if you really wanted to.

------
jason_s
See "Important Programming Concepts (Even on Embedded Systems) Part I:
Idempotence"

[https://www.embeddedrelated.com/showarticle/629.php](https://www.embeddedrelated.com/showarticle/629.php)

------
twothamendment
I recently soldered a wire to my garage door opener on the wall and ran it to
a relay and then to the pins on a raspberry pi. Knowing the state of the door
is key because the opener is just a toggle. I also have my alarm system hooked
up to the pi, so it checks the state before and after any request. Repeatedly
asking it to open will open it, or return success of it already is. Same with
close.

It took a bit of testing before I trusted it would all work the way I thought
it would, but now I user it and don't even think about it, it just works and
is handy to have.

------
billfruit
I know this is quite unrelated, and based on hazy memory of things from almost
10 years ago, DML statements in databases especially 'insert into' statements
are not idempotent as I remember; ie if you try to select a few rows from a
table table1 and insert them into table2 with same schema, if there were any
identical rows already in table2, then whole insert will fail. My thinking at
that time was that if these insert operations were idempotent, then there
would be no need to explicitly check for duplicates before the insert.

~~~
lathiat
At least in MySQL you can use “ON DUPLICATE KEY” to either ignore such things
or optionally execute an update statement to change something about the
matching row.

There is also REPLACE INTO

Assuming you have a relevant unique key setup of course.

------
inopinatus
See also: email-based click-to-confirm produces many false positives.

------
guelo
Is idempotency part of HTTP or just part of loose REST conventions?

~~~
phamilton
> loose REST conventions

REST is HTTP. "loose REST conventions" is when someone chose to ignore big
chunks of the HTTP spec.

In other words, you can build whatever you want (like SOAP) on top of HTTP and
ignore the spec that describes content negotiation, HTTP methods, Caching
policies, etc. It's still technically HTTP. But if you were to read the HTTP
spec and follow it to a tee, you'd build a REST application.

~~~
peteretep
> REST is HTTP

This is untrue. I hate to quote from Wikipedia, but it sums it up quite
nicely: "REST is not a standard in itself, but RESTful implementations make
use of standards, such as HTTP, URI, JSON, and XML"

More colloquially: REST is what happens when people mix up transport layers in
their head.

~~~
tzahola
HTTP is an implementation of REST.

~~~
phamilton
This is more the point I was trying to make.

~~~
peteretep
It's also untrue.

------
latchkey
I have a small (golang) agent that runs on over a thousand raspberry pi class
machines (not on the open internet).

The agent has a GET /reboot api because it is really convenient to be able to
just hit that url in a browser window when we need to.

Adding all the no-cache headers to the response seems to have worked well
enough to prevent browsers from randomly hitting the url.

I just added a check for the x-purpose header as well, thanks for the
suggestion.

~~~
XorNot
This still seems like really bad idea when the POST request is right there.

Serve a page with a button saying "are you sure"?

~~~
criddell
Do you really like having to confirm every action? For interfaces that you use
all the time, it's nice to be able to eliminate extra steps.

~~~
NoGravitas
If you're using it programatically (e.g., a script that's calling curl), it's
absolutely no trouble to use POST.

If you're using it from a browser, you can write it with a confirmation page
for simple browsers, but also use just a little javascript in normal browsers
to convert the GET to a POST and skip the confirmation page.

~~~
always_good
Also, if you have a confirmation page on GET, then it must be submitting to a
POST endpoint that you could still call directly.

------
mchahn
This garage door opening story reminds me of something that happened in the
50's. The first powerful comm satellites happened to use a frequency that
garage doors used (no id codes then). Garage doors opened and closed by
themselves. My grandmother had it happen to her.

------
daenz
These kinds of chaotic accidents are just going to get more frequent as
everything moves towards IoT

------
bawana
forgive my density, but why would you make a web page trigger a toggle when it
is loaded? shouldnt there be a button or some other user interaction to
initiate the state change?

Is it like loading a web page for the weather- so that when the page is loaded
it goes and 'GETS' the latest weather info? Is it for convenience? So that all
you have to do is go to a webpage and have it do stuff?

~~~
nwsm
I think there was a homepage with a "toggle" button, the toggle button
redirected to /toggle.

site.com/toggle then got added to his favorites by safari.

So it wasn't loading the site with the button, but the site that the button
redirects to.

~~~
wpearse
Correct. Site now has a form and a button. /toggle now responds only to POSTs,
and redirects back to /.

~~~
bawana
i must zsound so obtuse. How does redirection happen? If there is a web page
with a button, then what is /toggle? Is it another web page on his site? Isnt
a button some code in html on the index.html page?

------
zzbzq
The real problem here, as usual, is web browsers, the worst class of software
ever written. We constantly come across these CSRF-style bugs that are only
made possible by how stupid the browser and HTTP are, but instead of blaming
the culprit and trying to deal with the source, we blame ourselves for not
being accommodating enough. Fool me once, shame on me, fool me 5,000 times,
shame on me. Oh, and occasionally invent hackneyed fixes like CORS.

~~~
always_good
Craftsmen should understand the tools they use.

We expect it in every other industry.

Why do people like you always want to suggest that web developers shouldn't
have to learn the basics of the tools they use every day? This is page one
HTTP stuff.

This is the anti-intellectualism in our field. Where people are so used to
finding a YouTube video tutorial for the exact thing they want to do that
anything that's inherently hard (like client development) or requires some
extra knowledge to do correctly is somehow shitty and needs to be reworked.
More and more often it's somehow everything's fault but the craftman's.

It's that mentality that's coasting parts of our field into code monkey cost
center positions. Go somewhere like /r/webdev and watch how unresourceful the
beginners are and how bad the advice is.

------
jackpeterfletch
Or dont your doors to the internet.

------
sbussard
Too funny!

------
PotionSeller
>idempotent

what does this mean

~~~
emddudley
It's an important term in computer science. There is a good explanation on
StackOverflow which I found by searching for "define: idempotent":

[https://stackoverflow.com/a/1077421/111327](https://stackoverflow.com/a/1077421/111327)

> In computing, an idempotent operation is one that has no additional effect
> if it is called more than once with the same input parameters. For example,
> removing an item from a set can be considered an idempotent operation on the
> set.

------
downer68

      This, kids, is why GET requests should be idempotent.
    

Or, like, you know, how about a browser only sends a request when I'm actually
fucking asking for something, and doesn't try to fetch everything I've ever
thought about, with my every slightest accidental finger twitch against its
touch screen?

What happened to deterministic user interaction?

~~~
fenwick67
GET is meant to get, not set. Since 1.0.

[https://www.w3.org/Protocols/HTTP/1.0/spec.html#GET](https://www.w3.org/Protocols/HTTP/1.0/spec.html#GET)

> The GET method means retrieve whatever information (in the form of an
> entity) is identified by the Request-URI

~~~
downer68
So what?

If I never intended for the GET to be GOT, then the browser is just as much at
fault for such unintended consequences.

~~~
scottmf
That’s the whole point of HTTP request methods: it isn’t. GET should never
cause such side effects. The entire web is built with these principles in mind
precisely so that problems like this don’t happen.

If you want a slower browsing experience feel free to disable prefetching in
your browser, but this isn’t a hill worth dying on.

------
mrdiesel
This guy is stupid.

~~~
wpearse
You're stupid.

------
matte_black
This kind of thing shouldn’t even be a REST call. Use JSON RPC.

~~~
olavk
Why is that better?

~~~
matte_black
First of all “/toggle” is not a proper REST endpoint. In fact, that is exactly
what an RPC endpoint might look like. I can’t believe so many “developers”
miss this.

With JSON RPC, he would POST a JSON object to a /toggle endpoint which runs a
procedure to open or close his garage door.

If you want to be cute and conform to REST as much as possible, you would have
to treat your garage door like a resource, and then use PUT to send the entire
new state of the garage door to your API or PATCH to send the instructions for
how to change the existing state (or use the +json media type for patch if you
want to be lazy and just send a JSON object with updated key values). Your URL
would probably be in the form of “/garage-doors/garage-door-id”.

Except, his garage door is probably NOT a resource and has no ID or even a
serialized representation of it’s physical state. _It’s just a physical door_.
And it should be driven remote procedures.

Maybe you don’t need any of this. Maybe you are happy with just using GET and
pushing everything into REST and basically doing the wrong things. But that’s
how you end up with the problems in the article, by not respecting standards,
by choosing to be close enough to correct instead of _technically_ correct.
And frankly, if there’s any people who should strive for technical precision
it should be engineers.

I personally would not hire a single software engineer who chose to approach
this problem in the RESTful way without clear and deliberate reasoning for
doing so.

~~~
olavk
Yeah obviously he is doing it wrong, that is the point of the story. GET
methods should not have side effects. But wouldn't you have the same problem
if you sent a JSON RPC request using GET?

Clearly this is not a REST architecture, they are just using raw HTTP requests
as RPC's. I just don't see how the JSON RPC standard would help anything, it
just seem like an additional wrapper.

~~~
matte_black
You wouldn't send a JSON RPC request with GET. JSON RPC requires you to send a
JSON object in the body describing the method you are calling and the
parameters, and the version of JSON RPC you are using. That requires a POST.

You could just have a single /rpc endpoint that takes POST and use that to
serve multiple procedures for all sorts of things.

~~~
olavk
Yeah OK, so JSON RPC avoids this particular problem by simply not supporting
GET. But that is kind of throwing the baby out with the bathwater, since GET
is quite conventient when used appropriately.

~~~
matte_black
Consider what would happen if he didn't want to merely "toggle" his door, but
rather have it closed, definitively and once and for all.

Could he do that with /toggle? Does he know the state of the door well enough
to know if toggle is the right command? Can he even trust the state of the
door being told to him? What if it's already closed and it opens instead?

No. The only way is to send a message that directly says "Close the Door",
with no room for ambiguity on his intent.

JSON RPC excels at this, and in putting the door in whatever state he wants,
maybe half way, or 3/4\. How would you do this with "convenient" GETs? Use
query params? Multiple endpoints? By this point, idempotency is in the rear
view mirror and you're well on your way to having a clunky garage door system
fraught with bugs and strange edge cases.

~~~
olavk
I don't really have anything against JSON RPC but it is just a standard for
encoding a method name with dynamically typed parameters. You can say "close
the door" in JSON RPC, or you can just post the string "close the door" to an
URL. It doesn't make the service more robust or reliable to use an extra layer
of wrappers.

------
reza_n
To me this sounds like a CSRF problem. There's no token or session associated
with these calls, so a browser was able to inadvertently CSRF the calls.
Changing this call to POST or PUT would still leave this API vulnerable.

~~~
chrisseaton
It's not about access control, it's about the fact that browsers are free to
make speculative GET requests whenever they like, and they actively do to pre-
fetch pages. His GET end-point was pre-fetched by his browser, activating the
door. This would still happen even if there was a token or session associated.

~~~
reza_n
> This would still happen even if there was a token or session associated.

This is exactly the scenario a CSRF token is support to prevent. But I
understand your point.

------
PersistentCough
> You know how HTTP GET requests are meant to be idempotent?

No, they aren't. They aren't meant to be anything specific. They can be
idempotent, but generally these philosophical arguments are the net gain of
this kind of condescension.

