Hacker News new | past | comments | ask | show | jobs | submit login

The client perspective isn't relevant, because the server has no control over what the client does. That's why idempotency is restricted to the server. You're thinking of safety.



Of course it's relevant. Why else would a communications protocol bother to specify it?


Because the communications become useless if they do not accurately reflect the state of the server. Sending anything other than an error when the client does something it shouldn't (for example, calling DELETE on a resource that no longer exists) leaves the client in a state where it doesn't know what's going on.


The only meaningful measure of the server's state is in how it expresses that state via the communications protocol. As a client, what the server does internally is irrelevant, so long as it behaves consistently when I talk to it.

I find it farfetched that the spec authors would specify that an HTTP-compliant server should not do something completely unexpected in the face of a DELETE on a nonexistent resource. What's the alternative to "internal idempotency" here? To randomly restore the deleted item? To delete something else instead? Anything other than "note that the item is already gone and return" would be a bug. So why would anyone put this in the spec? They wouldn't, which is why the spec is clearly discussing idempotency with respect to the communications, and not with respect to the server's internal state (which again is not something the RFC mandates).

On the other hand, the RFC does specifically call out that clients should automatically retry idempotent operations in the event of a closed connection, which makes no sense if the communications will not be idempotent. The RFC also calls out that internal state may be changed in the face of an idempotent (and even a safe) operation, another indication that what's being specified is not internal server behavior/state (because if it's mutating state it's not internally idempotent).

> the client does something it shouldn't (for example, calling DELETE on a resource that no longer exists)

You're begging the question by assuming that a client should not call DELETE on a nonexistent resource. It's perfectly valid to interpret "DELETE" to mean "make sure nothing exists at this URL" (I believe the RFC does), in which case a delete of a nonexistent item is a successful call.


>The RFC also calls out that internal state may be changed in the face of an idempotent (and even a safe) operation, another indication that what's being specified is not internal server behavior/state (because if it's mutating state it's not internally idempotent).

Ah, now I see the crux of the problem: you've mixed up safety and idempotency. It is perfectly all right for an idempotent action to change state, as long as performing the same action twice is functionally no different from performing it once.

This is different from safety (which some call nullipotency), where performing the action once or twice is the same as performing it zero times: i.e. nothing changes. The HTTP spec notes that it has no way of actually preventing servers from ensuring that safe actions change nothing, but it still warns server developers against doing so.

But the final proof that idempotency is not with respect to communications comes from the spec itself: RFC 2616, section 9.1.2, first sentence. The spec even explicitly states that error or expiration issues can cause different responses on subsequent requests, which is what makes it clear that idempotency is not with respect to communications.

"Not Found" is an error condition with respect to the server. That is a fact of the HTTP server specification: the client wanted to do something with a resource that the server couldn't find. It might be that this condition is precisely what the client wanted, but the server has no way to know that: it can only answer from its own perspective. It is up to the client to sort the matter out on its own, but fortunately, this is not hard. A client that expects for resources not to be found from time to time need only listed for these cases, and deal with them however it wants to. The server need never know.

>You're begging the question by assuming that a client should not call DELETE on a nonexistent resource. It's perfectly valid to interpret "DELETE" to mean "make sure nothing exists at this URL" (I believe the RFC does), in which case a delete of a nonexistent item is a successful call.

Actually, the RFC doesn't say that. The relevant section (9.7) states that DELETE is for actual requests to delete something. Nothing else. To "make sure nothing exists at a URL", the proper method is GET. You can also use HEAD if you're worried about a large entity-body taking up too much bandwidth. OPTIONS would work too, and it has the advantage of only touching the metadata, but not all servers support it.


> Ah, now I see the crux of the problem: you've mixed up safety and idempotency.

That's not the miscommunication here. The reason I mentioned state mutation was only to clarify that the RFC does not dictate consistent internal server state. Even a "safe" call is only considered safe from the view of the caller. It also does not "warn developers" against changing state as a side effect of a "safe" call. It specifically states that this may be considered a feature, but that the user does not request any such side effects. Again, the concentration here is on the behavior of the communications, and not on the internal behavior of the server.

> But the final proof that idempotency is not with respect to communications comes from the spec itself: RFC 2616, section 9.1.2, first sentence. The spec even explicitly states that error or expiration issues can cause different responses on subsequent requests, which is what makes it clear that idempotency is not with respect to communications.

We're clearly reading this RFC differently. I see the error and expirations as being server-side. X expired? Sure, "GET X" will return a different result. Disk failed (aka error), certainly the response is going to change.

The RFC calls out changing the behavior in response to errors or expirations as an exception to idempotent behavior. I see this as confirmation that the server should behave consistency from the perspective of the caller except in cases where this is not possible.

> "Not Found" is an error condition with respect to the server. That is a fact of the HTTP server specification

I don't agree that "Not Found" is an error condition for delete. This is not in the spec. It's your interpretation of the spec. Nowhere in the RFC does it say "if a request comes in for X and X does not exist, a 400-level error should be returned". (If it did say that, PUT would be quite useless.)

> Actually, the RFC doesn't say that. The relevant section (9.7) states that DELETE is for actual requests to delete something. Nothing else. To "make sure nothing exists at a URL", the proper method is GET. You can also use HEAD if you're worried about a large entity-body taking up too much bandwidth. OPTIONS would work too, and it has the advantage of only touching the metadata, but not all servers support it.

You misunderstood what I was saying. "Make sure nothing exists" isn't an intention. It's a command. It's "Hey, server, make sure that when you return, nothing exists at location X." It's a delete, but a less "strict" version than yours, which is "Hey, go find out if something exists at X, remove it if so, and throw an error otherwise."

I don't think we're getting any closer to agreeing on this. I looked for a more definitive answer from one of the RFC authors, but couldn't find anything. It's just this same discussion playing out over and over with other people.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: