What developers don't get about Idempotency
Source: Dev.to
Quick question
Is a DELETE endpoint that returns 404 on subsequent calls idempotent?
If you said no because the response changed, this article is for you.
Idempotency is a concept that is often misunderstood, even by developers with many years of experience.
What is Idempotency
Wikipedia definition:
Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.
In computer science we can phrase it as:
Idempotency is the property of an operation whereby it can be applied multiple times without changing the result beyond the initial application.
Example GET operation
A GET request is typically idempotent because it does not modify the database.
For example:
GET /api/v1/users
No matter how many times you call it, the response is the same and there are no side effects.
POST, PUT, PATCH and DELETE operations
The confusion often arises with POST, PUT, PATCH, and DELETE.
Whether they are idempotent depends on the actual implementation, not on the HTTP verb alone.
POST operations
Consider a POST endpoint that creates users.
class User {
final UUID id;
final String username;
}
Request
POST /api/v1/users
Content-Type: application/json
{
"username": "manuelarte"
}
Response (first call)
200 OK
Content-Type: application/json
{
"id": "f2f7734c-1082-43cf-9b66-9161349ef154",
"username": "manuelarte"
}
Scenario A – A new user is created each time
Calling the endpoint again with the same payload returns a different user:
200 OK
Content-Type: application/json
{
"id": "c6fab354-c559-460b-a66c-5d0bad8f6aba",
"username": "manuelarte"
}
The endpoint is not idempotent because each request creates a new resource.
Scenario B – Same response as the first call
If the second call returns the same user as the first call:
200 OK
Content-Type: application/json
{
"id": "f2f7734c-1082-43cf-9b66-9161349ef154",
"username": "manuelarte"
}
The endpoint is idempotent: the state of the system does not change after the first request.
Scenario C – Different response code but no state change
Suppose the second call returns an error indicating the user already exists:
400 Bad Request
Content-Type: application/json
{
"code": "USER_CREATED",
"message": "user already created"
}
Even though the HTTP status differs, the endpoint is still idempotent because the underlying state (a single user) remains unchanged.
Idempotency is about the final state, not about the response code.
DELETE endpoints
A typical DELETE request is idempotent regardless of the response code:
DELETE /api/v1/users/{id}
- First call deletes the resource →
204 No Content. - Subsequent calls find the resource missing →
404 Not Found(or204 No Content).
Since the state after the first successful deletion is the same for all later calls, the endpoint is idempotent.
Non‑idempotent delete example
DELETE /api/v1/users/last
If each call deletes the currently last user (e.g., first call deletes user 5, second call deletes user 4, …), the state changes with every request, so the endpoint is not idempotent.
Summary and takeaways
- Idempotency means that consecutive calls with the same data do not change the system’s state after the first successful request.
- It is about state, not about HTTP methods or response codes.
- Understanding this helps with:
- API design – building services that can safely retry requests.
- Client implementation – handling varying response codes correctly.
- Contract testing – writing accurate tests for API behavior.
Next time you design or consume an API, remember:
- Idempotency = State doesn’t change after the first request
- HTTP methods suggest idempotency, but the implementation guarantees it.
For more details see RFC 9110 and resources on implementing idempotency with headers.