Thanks for the explanation!
I still don’t get how idempotency can typically be ensured without state. It very much depends on data model and application design. Even side effects like using a user’s lookup quota need to be handled at a higher layer than HTTP (I think?).
Yes it varies. Using the QUERY method doesn't automatically mean your app is idempotent - it means the browser, and any intermediaries, can assume it's idempotent. So when you go forward and then back they're free to reissue the request and you won't get the "this may repeat whatever you just did" popup.
If it's not actually idempotent but you're telling the browser it is, of course you may cause bugs. Same as GET.
> I still don’t get how idempotency can typically be ensured without state.
Well, how is "GET /index.html HTTP/1.1" made idempotent in practice without (additional) state?
Minor side-effects like quotas or request logging are generally ignored when considering the semantics of http methods. I don't see any complications for QUERY that don't already apply to GET. It just allows you to bypass the url length limit by putting the data in the body instead of the url itself.
Imagine a forum where comment ids are client-generated UUIDs, and comments are inserted with "ON CONFLICT IGNORE". Submitting the same comment twice would simply be a noop
But what the Query method really targets are things like a graphql query that can be multiple kb for a single query, but only reads data. Sure, it might count against rate limits, trigger logs, etc. But at a conceptual level resubmitting the same query should give the same result (if the data didn't change). And since you are only reading data, resubmitting is safe