6 ms·
It's a bit funny to see an IETF draft for this! Adding idempotency support to Stripe's API was one of the things I built while an intern in 2015. We've since r
by pokoleo 5y ago
It's a bit funny to see an IETF draft for this!
Adding idempotency support to Stripe's API was one of the things I built while an intern in 2015. We've since rewritten it almost entirely, but many the technical decisions made in 2015 still stand.
One of the things that IETF doesn't specify ("an appropriate response") is that Stripe's Idempotency API has a response body has the latest rendering of the resource. Here's what I mean:
# Set tax exempt status
curl /v1/customers/cus_AJ6m5vWl7scnn6 \
-H "Idempotency-Key: aaaaaaaaaa" \
-d tax_exempt=reverse
→ {id: 'cus_AJ6m5vWl7scnn6', object: 'customer', tax_exempt: 'reverse', ...}
# An unrelated request sets the customer's email
curl /v1/customers/cus_AJ6m5vWl7scnn6 \
-H "Idempotency-Key: bbbbbbbbbb" \
-d email='foo@bar.com'
→ {id: 'cus_AJ6m5vWl7scnn6', object: 'customer', tax_exempt: 'reverse', email: 'foo@bar.com', ...}
# Set tax exempt status with the first idempotency key:
curl /v1/customers/cus_AJ6m5vWl7scnn6 \
-H "Idempotency-Key: aaaaaaaaaa" \
-d tax_exempt=reverse
# The customer is re-rendered on the latest version
→ {id: 'cus_AJ6m5vWl7scnn6', object: 'customer', tax_exempt: 'reverse', email: 'foo@bar.com', ...}
- milofeynman 5y agoThat's very useful! I can't decide if the architecture is more complicated or simpler because of that. It helps avoid stale data showing up in the UI, etc. It seems like you just need to store the idempotency key and the request data (in case the data changes, to catch bad requests using same key...), but not the response. I think Amazon actually stores the response in a table for some amount of time (24 hours?), iirc https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/ https://aws.amazon.com/builders-library/making-retries-safe-... but I could be wrong.
- felixhuttmann 5y agoWhat I have always wondered about, in the stripe docs it says "Stripe's idempotency works by saving the resulting status code and body of the first request made for any given idempotency key, regardless of whether it succeeded or failed. Subsequent requests with the same key return the same result, including 500 errors." which indicates that the idempotency functionality is created in a kind of layer around the main application functionality, and thus the request from the idempotency layer to the main app is not itself idempotent. So the idempotency key protects against faults on the network between the client and stripe's idempotency layer, but not against stripe-internal faults between the idempotency layer and the application. Is that the case? Why is the idempotency not achieved by using an idempotent database transaction or atomic operation? What is the value of responding repeatedly with a 500 if the original 500 was caused by a transient error? Adyen seems to similarly implement the idempotency in a separate data store (https://docs.adyen.com/development-resources/api-idempotency#designing-for-resilience https://docs.adyen.com/development-resources/api-idempotency...). Both stripe's and adyen's implementation seem to not treat transient faults within their own systems correctly.
- foolfoolz 5y agothese seem extreme for most apis but are likely very good at preventing double charging. a “normal” api call usually costs nothing. i bet stripe and adyen have apis with an average cost per call (to someone) being like $20-$30 the cost to undo a charge is high in people and reputation
- polynomial 5y agoHow could their API possibly cost $20-$30 per call? How could that even be a business model? Clearly, I am missing something here.
- terinjokes 5y agoI suspect the OP meant to say charge instead of cost.
- polynomial 5y agoah that makes sense.
- foolfoolz 5y agounrelated but fun fact: AWS CloudHSM v1 (deprecated now) had a $5,000 api call. that was the cost to create a cluster.
- wdb 5y agoDon’t some bank system transfer like the U.K. cost like ~£25 per transaction?
- joshribakoff 5y agoMany developers conflate idempotency and purity. It appears stripe is trying for purity, two requests always have the same response. This is likely misguided. Idempotency would be like the API failed to generate the success response, but the backend did issue the money movement. On subsequent retries what matters is that it doesn’t do a duplicate money movement. The client ought to get a request indicating the money was successfully moved (since it was), perhaps with the earlier timestamp as a way of indicating it was already moved. Or it ought to get a special response that indicates the client can stop retrying Sending the same error upon success sounds like the client has no way to know when to stop retrying. Sure it makes the API pure, but what problem does it even solve?
- slt2021 5y agoare you mixing command and query together in one request? i thought it is a bad practice. mutating data is command and is a separate request and fetching customer details is another request
- chrismorgan 5y agoOn the contrary, for remote APIs like this having commands return the resulting state is the only sane path; otherwise you get mandatory inefficiency (doubling latency) and race conditions.
- joshribakoff 5y agoCQRS doesn’t obviate race conditions. Especially if multiple commands can be in flight at the same time (the response can still be received out of order), or if there are multiple clients mutating the same resource.
- chrismorgan 5y ago> CQRS doesn’t obviate race conditions. I think you may be talking at cross purposes with me here. I’m saying that command–query separation¹ causes race conditions. Having the mutating API return state is the only way to obtain the value of the resource at the time of mutation. — ¹ CQS; CQRS, where you use different representations for command and query, is not necessarily applicable here.
- joshribakoff 5y agoYes you’re right. I meant to write that abstinence from CQ[R]S doesn’t prevent race conditions.
- joshribakoff 5y agoIt’s not bad practice. CQRS is just a pattern with pros and cons.
- manigandham 5y ago