Closed olijaun closed 2 years ago
@olijaun
Happy to discuss these. Few comments below
1- The write-up is more about returning the exact processing state of the idempotent request if it is already processed. A request is either successfully processed or failed. Successful processing means a 200 response with the current resource state and a failed response usually is a 4XX/5XX response with error details. A Retry mostly takes place for a scenario when the connection to the client is lost before the server returns (or writes) the completed processing state of the request, which means the server should always emit the completed processing state (the exact status of the request processing, with an exception for few recoverable errors). Pls note that this is a different scenario than the "Request In Flight" (i.e. Request processing is in progress and the server receives a duplicate request- In this case returning an error code (409) would be fine and the write-up describes this scenario).
2-Idempotence Contract= Key + Fingerprint. Key is only used for lookup the payload in the idempotence cache (The request payload is then processed idempotently.). If only the key is used to check the idempotent condition, when a client reuses a previously used key for a new payload, the idempotent implementation would wrongly return the response status of the old request payload for which the key was previously used (wrong behavior) VS when both key + fingerprint are used as the contract, it is an error condition and the server responds with an errror, which is the correct behavior. What are we suggesting here? Are we saying that we soften the language and use SHOULD instead of MUST?
3- I'm good with Idempotence-Key
if that is the right key name from English language standpoint but there are already widespread usage of Idempotency-Key
in public APIs:-)
@jayadeba
Thanks for your answer. Just to be clear: I'm not talking about any mistakes in the spec. It's - as you say - about softening the language and use SHOULD instead of MUST. I could of course always use a proprietary header for my purpose. So it is up to you what "softness" you are willing to accept :-)
I get your point and it absolutely makes sense. I also get the reason of the 409 and I wouldn't change anything about the 409-case. I'll give you an concrete example to explain my point: Imagine a simple "Person-Resource". You create a new person by posting a JSON:
POST /persons
Idempotency-Key: 1a2f0bd1-2a19-4b89-ae19-818562005d78
{
"name": "John"
}
<client has a timeout (or has lost connection) and does NOT receive the following response:>
200 OK
Content-Type: application/json
{
"id": "de2e865b-d66c-4f88-878d-071c1514c10b",
"name": "John"
}
Now assume another client changes the "name" from "John" to "Bob" using PUT or PATCH.
Now the client that previously had a timeout retries the request:
POST /persons
Idempotency-Key: 1a2f0bd1-2a19-4b89-ae19-818562005d78
{
"name": "John"
}
200 OK
Content-Type: application/json
{
"id": "de2e865b-d66c-4f88-878d-071c1514c10b",
"name": "John" // the name in the database is now "Bob" but we have to return "John"
}
What I understand from the RFC is that it MUST return "John" here although the name has been changed to "Bob" in the meantime.
As I said before: this makes completely sense but is not trivial to be implemented in a simple CRUD-Application that just stores the "current state" in the database.
Therefore I suggest to introduce the possibility to alternatively respond with a 2xx-StatusCode other than 200 to indicate to the client that the request with the given Idempotency-Key has been (successfully) processed already (maybe a 204 with a link to "idempotency"?). This means of course a bit more complexity on the client side and a bit less complexity on the server side.
Regarding 2): yes, I'm suggesting to soften the language and make the "Fingerprint" an optional part of the Idempotency-Contract.
As I said before: I see that this is somehow a contradiction to the term "Idempotence". My reasoning is purely pragmatic.
@olijaun Good points. Thanks for the explanation.
1-In section 2.6, it makes sense to soften the language from MUST
to MAY
or SHOULD
. Receiving a stale resource representation is ok for many clients. If a client can't tolerate a stale representation, it can always fetch the latest resource representation by doing a subsequent GET. Event with a GET, on the server-side, in the distributed architecture, there's as well no guarantee that the client would receive a latest representation. Also returning the earlier processed response in case of a retry makes things simpler to implement, if someone wants to implement request idempotence as a common edge service at the API gateway layer. Any 2XX response is ok for this scenario (although, for resource creation POST operations, 201 with resource link or 200 with the complete resource representation are preferred)
2-Regarding 2.7, IMO, making idempotency Fingerprint optional MAY weaken the idempotence contract & condition. But we are open to hearing more views on this and we can eventually decide the suitable language.
@olijaun We have softened the language to SHOULD
for the behavior that the server MAY respond with the latest resource if the resource was modified by another client while the original client's request timed out. So this issue is resolved.
We also made idenpotency key optional (An idempotency fingerprint MAY be used in conjunction with an idempotency key to determine the uniqueness of a request.
).
Resolving the issue.
Hi
It's great to see this RFC. Thanks for your work! I have three points I'd like to discuss:
Thanks and kind regards Oliver Jaun