[FEATURE REQUEST] support for idempotent API requests
Right now all of my orchestration / automation scripts have to make two calls to the API every time I want to interact with a resource at Linode. First I have to check if it exists with a
GET request, register the response, and then based on the answer, I have to make either a
POST request to create the resource if it doesn't exist, or a
PUT request to create the new resource.
I would really appreciate it if there was an
overwrite: true parameter on your POST (create resource) related endpoints so that I can make idempotent calls, in essence, letting the POST, fall back on a PUT. Or put another way, similar to in MySQL's
... ON DUPLICATE KEY UPDATE.
Using this overwrite parameter would let those API endpoints remain backwards compatible and with expected behaviours, but it would also reduce overhead at the server, on the network, and would reduce the required complexity and opportunities for errors at the client end in our scripts.
Please, please, pretty please! :)
As a convention in REST APIs, POST requests are only used to create resources, not usually update, so I’m not sure if Linode would change this (although I can’t speak for them obvs.)
There is also the ambiguity of what is a unique resource? For example: to you, a duplicate DNS record has the same name, same type on the same domain. But to someone else it isn’t (think DNS round-robin.)
As a possible interim solution, can you not store the Linode resource ID in your app/system? If you have an ID, you make a PUT request, if you don’t, you make a POST and retain the ID returned?
You could then handle a fallback case if you get a 404 from the PUT, the item has been deleted, so you issue a POST and retain the new ID.
Just a thought :)
Hey @andysh, I'm aware that it is non-standard as far as REST principals are concerned, but REST is a concept, not a rule book.
Every orchestration system out there these days is aiming for idempotent runs, and unless some real work is going to be done updating the completely inferior implementations of the V4 API in those systems (just take a look at what you can do in Ansible, it's limited to create and delete a linode, nothing else), then this would be the next best thing.
Adding a single
overwrite parameter would not force anyone to break their personal adherence to REST principals, and those using it should have a concept of how it would work in their use case, but it would expand the ability of the API to deal with modern use cases, particularly making the development cycle much much easier.
Like I said above, there are no rules, only common practices, there are in fact a number of reasons where the jobs of PUT and POST are reversed, it all depends on the implementation and it's goals. That said, I'm not looking to change behaviours, only augment them. PUT is often idempotent right out of the gate, and is also commonly used for CREATE and UPDATE, so I'd be just as happy with the ability to make a PUT request WITHOUT a required ID so that the system generates one if the unique record does not already exist.
With regard to coding a workaround, that's the reason I posted this, it's right there in my first paragraph, I have to write 4x as much code to accomplish this one task…
First I have to check if it exists with a GET request, register the response, and then based on the answer, I have to make either a POST request to create the resource if it doesn't exist, or a PUT request to create the new resource.
This is not idempotent. Idempotent is being able to make exactly the same request with exactly the same data and get exactly the same response. If the record is new, I get it's details, if it's updated, I get exactly the same details. They can still be differentiated with response codes, i.e. 201 CREATED, 200 UPDATED (both of which are standard responses for REST interfaces).
There are lots of ways to skin this, but there is certainly no rule that says it can't or shouldn't be done.
EDIT: Sorry Andy, I noticed you mentioned storing the state of the record at my end… that breaks the ability to use a dynamic inventory. What's to say that some other influence doesn't change the state of the record in question outside of my control, or at least out of control of a micro-service for instance. Heck, I could even change it manually in the web console for some reason and just want to bring it back to a consistent state. It just comes down to having to code around question marks, making idempotent requests eliminates sooooo much extra and unnecessary work.
Just in case there are any Linode Staff checking this out…
A suggestion for making this relatively easy would be to hash the request data, then store that hash as meta along with the created record, so that subsequent uses of the same request, in turn using the same hash, would match the existing record and overwrite it.
@Linode Any chance this idea can be bounced off the Dev team to see how feasible it would be?
I would like to second this request on adding idempotency to the linode API. As someone with over 20 years experience on developing fault-tolerant systems, I would not feel safe developing against an API that does not support idempotency.
Look at how paypal does it:
They know their stuff, and they have to, since they are dealing with payments. Now, I know linode is not a payments processor, but I believe linode's APIs should be treated as importantly as these payment APIs, and hence the design deserves a greater scrutiny for the sake of fault-tolerance.
Please do consider adding idempotency to the POST APIs.
I'm coming to this late, but I'm trying to use Ansible to manage some linodes along with a nodebalancer, and I think this issue is what's making me go a little crazy.
I end up having to use the Ansible uri module to make calls, and then stuff the results into a var, etc. It would be wonderful if someone would share their playbooks for doing this so I can just work from a base, instead of re-inventing this again. And probably doing it wrong since I'm a newbie to Ansible.