What Is Idempotent in REST?
The PUT method is idempotent. An idempotent method means that the result of a successful performed request is independent of the number of times it is executed.
Idempotency is also something discussed in the SOA Design Patterns. Over the years there has been a lot said about REST and its perceived benefits over other approaches, with idempotency just one aspect that is often assumed to be understood yet typically not investigated fully. However, a recent posting on the Service Oriented Architecture mailing list has brought a lot of discussion around a concept that many had appeared to assume was fairly straightforward. The inital post starts with:
Currently I am looking at Idempotency of our services and coming up with a prescriptive guide for the enterprise in creating cases you create idempotent services. The question is do does all services need to be idempotent ? Is it realistic ?
It references another blog entry, where that author makes the following assertions:
Of course, implementing idempotency can be complex for the service provider. And complexity costs money. That's probably the real reason why idempotent services are so rare. [...] But once a service is made idempotent, it is foolproof, and can guarantee data consistency across integration boundaries. Services should be made idempotent. It should be an architectural and service design principle. Especially so for services which are used by many service consumers. You can't really push out your own complexity of keeping data consistent to your consumers, can you? The consumers are your customers, you should treat them as such. You gain more customers if you make it easy for them.
This initial posting has generated a lot of responses, including from Cap Gemini's Steve Jones who has this to say:
Idempotent is one of the great rubbish phrases of IT, what it means is 'idempotent in memory'. If you have a comment service with an update capability then clearly from the perspective of the invoker the service has to maintain and manage state. What you mean is can it be horizontally scaled in memory. If you update state, including within a database, then you cannot be idempotent. Idempotent is where you call the same function with the same value and the result is exactly the same, that is the mathematically definition. If you ever update state then you are not idempotent, that its 'a database update' doesn't change anything.
Mark Baker, who has posted a lot on REST in the past, responds to Steve:
There are non-idempotent state updates, like your comment example, and there are idempotent updates that set some datum to some specific value... since obviously if you do that multiple times with the same input, the result will be the same.
Steve agrees with Mark to a point: an operation is mathematically idempotent if it changes nothing with the same input value. However, if there is an update to any state caused by the operation, e.g., it reocrds the latest time of the request, then it is not idempotent.
I've been quite 'impressed' at how people misuse the term these days in IT, I've seen several occasions where people claimed something was 'idempotent' because it wasn't stateful in-memory, even though its consumer effect was recording transactions.
Mark agrees with Steve's strict definition, but believes it does not apply in the context of the original request: idempotency in distributed systems:
[...] the word can only meaningfully refer to the interface and not to the implementation. So if I define an operation, say "set", and define it to be idempotent, then that's all that matters to clients, even if a logentry is generated as part of an implementation of that interface.
Another respondant, Ashaf Galal, makes the assertion that all "reading services" are idempotent since the service is only returning data. However, as Steve points out, this is too simplistic a view and whilst an operation may appear idempotent its implementation may be anything but idempotent (again raising the question about whether this distinction is important):
[...] reading capabilities don't have to be idempotent. 'getNextIterator()' is a reading capability that isn't idempotent as it would increment the iterator. A banking request for a balance wouldn't be idempotent as the request would create an audit log. The returned result might be the same for two subsequent calls (if not changes have happened) but the log entry would be different.
Ashaf responds to Steve by stating that idempotence is a property of the service and not its interface.
The client need to get a proper response from the servcie and he doesn't care if the servcie is idempotence or not, logging or not.
So what do others think? Is there still a misunderstanding with what idempotency means? Does it matter if an operation that is supposed to be idempotent actually makes changes to some state, such as updating a log as Steve mentions?
Thomas de Bodt
Concerning the definition, I think we mix up idempotent, stateless and readonly. An idempotent operation is not always readonly, it only ensure that if the operation is called twice with the same parameters the post-condition is unaffected. This concern the core business of the Service, i.e. the state of the business domain, and not the cross-business dimensions like security, logging, audit which does not affect the business messages exchanged with the Service consumer.
Idempotent is not rubbish
Put idempotence into context:-)
The primary goal of the function is to update an entity. In this sense the PUT operation is idempotent in the business context. It does not matter whether you execute the same PUT operation once or many times, the result (ie. the updated record) should be the same.
Meahwhile if the PUT operation is logged than obviously each log record will be different. In this sense (the PUT operation as a whole or the PUT operation in the administration context) it is not idempotent.
Since usually you log everything, no operation is idempotent as a whole. Hence one might ask why idempotence might be interesting at all? One such situation could be reliablilty in system integration. Consider the situation where you are integrating your system with an external one (which is quite typical with REST isn't it:-)) and you want to provide reliability (ie. against network failures or such). In this case idempotence might be your friend since you can retry the failed operation as many times as you want. Well the order of execution could matter (ie. PUT 1 retry PUT 1 PUT 2 is not the same as PUT 1 PUT 2 retry PUT 1) but that's another story:-)
Re: Idempotent Service
An idempotent operation is not always readonly, it only ensure that if the operation is called twice with the same parameters the post-condition is unaffected
Bingo. That right there summarizes what "service" idempotency means to me. It should not matter to the user (be it a person or an automated system) if an invoked service is truly read-only/mathematically idempotent or if it writes an audit log. It should only matter if its post-conditions hold.
Now, the question is whether the service's post-conditions are correct or not, a question that sits squarely in the realm of requirements specifications, and systems validation & verification.
Thus, I think that instead of worrying whether a service is idempotent or not, the key worry is whether the service adheres to a specific set of functional and non-functional requirements, and whether such requirements make sense/are valid.
The entire set of valid (and validated) requirements will dictate what idempotency is and what services will meet that criteria (and perhaps by how much if the requirements call for a idempotency gradient.)
For instance, the expected result of various calls to update a registry, if it has the same input values, the user expect to have the same result. If the inputs are different, the expected result will be different…
You may not search for idempotence, but you found it in some calls.
Re: Idempotent Service
From the HTTP spec above:
"the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.
"Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them."
So it's the user's perspective that matters for idempotence. If logging does not affect the user (say it is only used for auditing and diagnostics) then performing logging within a GET request for a resource does not stop it being idempotent.
As an example, if a GET request had a side-effect like erasing some of the user's data (or another user's data) or sending something to a printer, then that would break idempotence and would matter.