> GET requests will be sent, but they are supposed to be idempotent so if your server is implemented in a sensible way, it cannot cause any adverse effect, and reading the response is all that matters for GET requests.

This is not correct. Safety and idempotency are two different concepts. Safety is when a request does not result in a state change. Idempotency is when the outcome is the same whether you make the request once or several times.

GET is defined to be both safe and idempotent. Clients can make GET requests without explicit human intent driving them because they are safe, not because they are idempotent.

DELETE is not defined to be safe but it is defined to be idempotent. This means you need human intent to drive it, but clients can retry as much as they like because whether you ask to delete a resource one time or a hundred times, the result is still the same – the resource is deleted. Obviously making DELETE requests can result in adverse effects even though it is idempotent.

POST is neither safe nor idempotent, however it’s subject to some unintuitive rules when it comes to things like cross-origin requests for historical reasons.

I wasn't aware of the distinction between “safe” and “idempotent”, TIL, thank you.

> DELETE is not defined to be safe but it is defined to be idempotent

This one puzzles me though. How can DELETE be idempotent? If the first request works then the second one should return a 404, as the key to delete doesn't exist anymore.

HTTP requests are not RPC calls. The end state of a DELETE request is that the resource does not exist. If you make the request once, the end result is that the resource does not exist. If you make the request twice, the end result is that the resource does not exist. The spec. allows for the actual response to differ; the important thing is that the state is the same regardless.

Response is implementation detail: a 404 on second request is one way to do it, a 202 would be another, or 200 with some sort of response to distinguish (e.g. { changed: boolean }).

Idempotency just means no state mutation on subsequent request.

> 202 would be another

Then you'd return 202 on a request to delete any invalid element, which really doesn't sound right.

> 200 with some sort of response to distinguish (e.g. { changed: boolean }).

Sounds even worse, and much like APIs that returns 200 with a payload saying {error:"not found"}

> Then you'd return 202 on a request to delete any invalid element, which really doesn't sound right

It depends on your use-case if you care about this or not. If you do care you will have to handle it either way somehow.

But if you want an idempotent API then a success is more appropriate IMO than an error.

Request failed successfully

It's the graphql way.

> This one puzzles me though. How can DELETE be idempotent?

It's the textbook definition of idempotence. So much so that wikipedia's article on idempotence mentions it and provides links to primary sources.