Starting Point:
According to https://www.rfc-editor.org/rfc/rfc9110.html#name-safe-methods, when making a GET call, the client is not requesting and not expecting the call to lead to any state changes.
Request methods are considered “safe” if their defined semantics are essentially read-only; i.e., the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource.
Of the request methods defined by this specification, the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe.
In my understanding, the following application violates the spec, because current-value
is in the DB state of /objects-with-value/1
and changes with each call.
GET /objects-with-value/1
{
"id": 1,
"local-variables": {...}
"current-value": 123.0
}
where
current-value
depends onlocal-variables
and also depends on the current day, and is the result of a call to an external servicecurrent-value
is persisted in the DB state of/objects-with-value/1
Question:
My assumption is that an application which does not violate the above mentioned RFC would rather look like this:
current-value
is not in the DB state of/objects-with-value/1
- instead, it is calculated on each
GET
call - the external call is cached
The assumption is only correct if the population of the cache is not considered a state change. Hence, the question: Is caching external calls considered a state change in the context of safe HTTP methods?
1
The RFC clarifies this in the next few paragraphs:
This definition of safe methods does not prevent an implementation from including behavior that is potentially harmful, that is not entirely read-only, or that causes side effects while invoking a safe method. What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it.
In other words, you can make state changes all you want on the server as long as it doesn’t create any problems (or you as the host are willing to accept responsibility for those problems).
Another sentence that is relevant:
The purpose of distinguishing between safe and unsafe methods is to allow automated retrieval processes (spiders) and cache performance optimization (pre-fetching) to work without fear of causing harm.
For a safe method, whether you are caching in your server or some proxy layer between your server is caching your response shouldn’t matter. It doesn’t really make sense to say that it’s OK e.g., for a client browser to cache a response from the server, but the server can’t cache the data used to create the response.
Now, to be clear, it’s not necessarily true that, in every particular case, caching is appropriate and won’t result in issues. You need to consider the consequences of that. But it doesn’t change whether your operation is safe.
Context matters.
For example, GET endpoints may be audited for who accesses what. The get logic may log some debug/trace messages along the way. A security token might get regenerated as part of the auth flow. Monitoring will register the incoming request and factor it into its graphs and stats.
All of these examples entail some kind of state change in some part of the system due to receiving a GET request, but they don’t invalidate the general idea that a GET request does not change the application’s state.
What the guideline indicates is that an API should not be designed in a way that a consumer has an expectation that state changes when they send a GET request. It focuses on the designed application behavior as far as the consumer is concerned; which is different from the private application implementation (which may contain secret operations or automations that don’t necessarily play by the same rules).