-4

I see two possible interpretations of the semantics of request methods defined in the HTTP specification RFC 7231:

  1. The intended effect of a request method is fully defined by the HTTP specification (e.g. for GET, retrieving a representation of the target resource) and any extra effect implemented by the target resource’s owner (e.g. setting a thermostat to a given temperature) is a side effect of the request method, i.e. the user is not responsible for it.
  2. The intended effect of a request method is partially defined by the HTTP specification and any extra effect implemented by the target resource’s owner which does not violate the properties of the request method (safe, idempotent, or cacheable) is an intended effect of the request method, i.e. the user is responsible for it.

Which of these two interpretations is the correct one?


The interpretation is important to get right because it has major implications. For instance if the extra effect is setting a thermostat to a given temperature (which is idempotent but not safe),

  • interpretation 1 implies that it will be an intended effect if it is implemented with POST (since its intended effect is target-resource specific), and it will be a side effect if it is implemented with GET, HEAD, PUT, DELETE, CONNECT, OPTIONS, or TRACE (since their intended effects are not target-resource specific);
  • interpretation 2 implies that it will be an intended effect if it is implemented with POST, PUT, DELETE, or CONNECT (since they may not be safe), and it will be a side effect if it is implemented with GET, HEAD, OPTIONS, or TRACE (since they must be safe).
  • 3
    You say this has "major implications", but your example seems to just restate your premise. What does it actually mean for something to be an "intended effect" versus a "side effect"? What does it mean for the user to be "responsible for" an action? It might be possible to say whether setting a thermostat using a PUT request is compliant with the current HTTP specification, but I'm not sure that's what you're actually asking? – IMSoP Jul 07 '21 at 22:12
  • @IMSoP ‘What does it actually mean for something to be an "intended effect" versus a "side effect"?’ It means that the user intended the effect, he is responsible for it. ‘What does it mean for the user to be "responsible for" an action?’ See RFC 7231: ‘Likewise, a safe request initiated by selecting an advertisement on the Web will often have the side effect of charging an advertising account.’ – Géry Ogam Jul 07 '21 at 22:23
  • @IMSoP I did not invent the distinction between an intended effect and a side effect, it is in the HTTP specification. It defines a side effect as: ‘What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it.’ – Géry Ogam Jul 08 '21 at 10:10
  • @Maggyero When I did a GET request to /restart I intended for the device to restart, didn't I? But when Googlebot did a GET request to /restart it didn't. – user253751 Jul 09 '21 at 10:05
  • @user253751 Could you develop? – Géry Ogam Jul 09 '21 at 22:35

2 Answers2

3

I don't think the RFC is attempting to define "intent" and "side effect"; rather, it is referring to them as already existing concepts in the minds of implementers.

If you have an implementation where method X on a particular resource has effects A and B, the RFC is not going to provide a classification of A and B as either "intended effect" or "side effect". The RFC is going to classify the whole implementation as either compliant with the specification, or non-compliant.

The reason "intent" is relevant is that the specification acknowledges that side effects exist in the real world, in the same way that every change breaks someone's workflow. Defining a server implementation that writes to a log file when it receives GET requests as non-compliant would not be useful, so the RFC allows the implementer to make a judgement call about the results of "reasonable use":

Likewise, reasonable use of a safe method is not expected to cause any harm, loss of property, or unusual burden on the origin server.

So, if action A is the primary intent of the request, and action B can be reasonably viewed as a side effect, then action B can be ignored for the purposes of judging specification compliance. The distinction is as much philosophical as it is technical.

To take your example, if a server implementation specifies in its documentation that a particular request will set the value of a thermostat, and a client makes that request, that is clearly the intent of the request. If the request uses a GET method, then the implementation is not compliant with the HTTP specification, because the method is intentionally "unsafe".

If, on the other hand, there is something elsewhere on the server reading the logs of incoming requests and adjusting the thermostat without any knowledge of the client, then that could be considered a side effect of those requests. The server implementation could then be considered compliant with the specification, as the client is free to act as though the side effect does not exist.

IMSoP
  • 5,847
  • 1
  • 21
  • 26
  • Thanks. Yes we have three things: the HTTP specification (e.g. GET’s intended effect is A), the server specification (e.g. GET’s intended effect is B), and the server implementation (e.g. GET’s intended effect is B and its side effect is C). But my question is: for the server implementation to be compliant with the HTTP specification: 1. Should the intended effect of the former equal the intended effect of the latter (i.e. B = A)? 2. Or should the intended effect of the former include the intended effect of the latter (i.e. B ⊃ A) and its properties (safe, idempotent, or cacheable)? – Géry Ogam Jul 08 '21 at 12:41
  • @Maggyero I don't agree that there are three things. There is a piece of software, where a GET request has effects A and B; and there is a judgement call that effect A is the "intent" of the request, and effect B is a "side effect". The HTTP specification doesn't define a third effect, it provides an answer to the question "is a GET request with effect A compliant?" It does that by defining certain properties that effect A "must" have - "safe", "idempotent", etc. There are many aspects of the effect the spec has no opinion on, such as whether you read the resource from disk or an SQL database. – IMSoP Jul 08 '21 at 13:08
  • So according to you a server implementation can ignore the definitions of the methods given in the HTTP specification (e.g. replace the target resource’s state for PUT) and only take into account their properties (e.g. idempotent for PUT)? For instance, a server implementation that does nothing when receiving a PUT request (instead of replacing the target resource’s state) would be compliant with the HTTP specification since doing nothing is idempotent like required for PUT? – Géry Ogam Jul 08 '21 at 13:45
  • 1
    @Maggyero No, that's not what I said at all. Think of it like this: the specification lists a set of tests which the implementation must pass to be compliant. For a PUT request, that includes both "the effect is idempotent" and "the effect is to replace the target resource's state". Doing nothing doesn't pass those tests, but there are an infinite number of effects that do pass them: overwriting a file on disk, updating a row in an SQL database, setting the target temperature on a thermostat, or moving a garage door, could all be considered "replacing state", so would pass that test. – IMSoP Jul 08 '21 at 14:57
  • I don’t know why I did not conceive setting the target temperature on a thermostat or moving a garage door as a replacement of the target resource’s state, somewhat thinking that a resource is restricted to some documents (disk files) or something like this. But seeing a resource as (an abstraction of) a thermostat or a garage door makes a lot of sense now that I think about it! – Géry Ogam Jul 08 '21 at 19:12
  • With this new vision, let’s imagine that the server implements two resources: a thermostat and a garage door, and that it responds to PUT requests on the thermostat resource by setting the target temperature on the thermostat and closing the garage door, both effects being specified by the server (i.e. intended effects). Would that implementation be HTTP compliant? It would pass PUT’s test of idempotence and test of replacement of target resource’s state, but it would also replace the garage door resource’s state so I have a doubt. – Géry Ogam Jul 08 '21 at 19:24
  • 1
    @Maggyero I guess at that point, the resource would represent "the thermostat and the garage door" as a single resource. I don't think the HTTP spec itself has much to say about what counts as "a resource", except that actions on it should be consistent, e.g. after that PUT a subsequent GET should return the new state of both thermostat and door. A less artificial example might be updating a user's name in a database and simultaneously saving a new avatar image in a file store. There might be other reasons not to design your API that way, but I don't think you'd be breaking the HTTP spec. – IMSoP Jul 08 '21 at 21:06
  • I see, PUT’s definition (replacing the target resource’s state) constraints what the target resource represents. Now with the same example, let’s imagine instead that the server responds to PUT requests on the thermostat resource by setting the target temperature on the thermostat and deleting the garage door resource, both effects being specified by the server (i.e. intended effects). Would that implementation be HTTP compliant? It would pass PUT’s test of idempotence and test of replacement of target resource’s state, but it would also delete the garage door resource so I have a doubt. – Géry Ogam Jul 08 '21 at 22:27
  • @Maggyero Again, it wouldn't be "the thermostat resource" if it consistently affected other things, even if it's name was spelled "/thermostat"; and "deleting the garage door" has no meaning (would you attach explosives to it?) I'm not sure what you hope to gain from coming up with all these examples. The HTTP spec isn't there to tell you how to build a good API, it's there to set a baseline that clients and servers can both expect. – IMSoP Jul 09 '21 at 07:12
  • (By ‘deleting the garage door’ I meant removing its URI from the URI space, like if DELETE /door had been called.) I think that the underlying question behind my examples was: are the method definitions in the HTTP specification (e.g. for PUT, replace the target resource’s state) exclusive (i.e. only replace the target resource’s state and do nothing else) or inclusive (i.e. at least replace the target resource’s state and do something else if you want) for testing the compliance of the intended effects of a server implementation? – Géry Ogam Jul 09 '21 at 09:16
  • 1
    @Maggyero DELETE shouldn't remove the URI, it should remove the resource represented by that URI. It makes no sense to have a request which means "leave the door where it is, but stop anyone examining or changing it". As for the rest of it, there's always going to be an element of subjectivity in determining what's a reasonable definition for a resource, and what it means to update the state of that resource. It might be reasonable for PUT /door to set the alarm, and therefore change the result of GET /alarm; it would be more surprising for it change the result of GET /fridge – IMSoP Jul 09 '21 at 11:24
  • +1 for the more reasonable example. I am realizing that it is not the enclosed representation in the request which defines the target resource as comprising the garage door and the garage alarm. The requests could be PUT /door {"door_state": "close", "alarm_state": "on"}, but also PUT /door {"door_state": "close"}, PUT /door {"alarm_state": "on"}, or even PUT /door {}. What defines the target resource are the things that change state as part of the intended effect of the server, i.e. the fact that the server closes the garage door and turns on the alarm when it receives a request. – Géry Ogam Jul 09 '21 at 18:03
  • Are you sure that DELETE should not remove the (URI, resource) tuple from the server mapping between URIs and resources and instead should remove the resource itself (i.e. destroy it)? Yet the specification explains: ‘The DELETE method requests that the origin server remove the association between the target resource and its current functionality. In effect, this method is similar to the rm command in UNIX: it expresses a deletion operation on the URI mapping of the origin server rather than an expectation that the previously associated information be deleted.’ – Géry Ogam Jul 09 '21 at 18:03
  • I am finally accepting your answer because it gave me a deeper understanding of HTTP: 1. It articulates the HTTP specification, the server specification, the server implementation, and HTTP compliance. 2. It considers the result of interacting with physical devices as part of resources’ states. 3. It allows resources spanning multiple physical devices. Thanks for your patience Rowan! – Géry Ogam Jul 09 '21 at 23:47
  • Back to my original question of interpretation, restated correctly it was: are the method definitions in the HTTP specification exclusive (e.g. for PUT, only replace the target resource’s state) or inclusive (e.g. for PUT, at least replace the target resource’s state)? And the answer is of course exclusive, which corresponds to my confused interpretation 1, since an inclusive method definition would for instance allow a PUT which replaces the target resource’s state, and at the same time retrieves the target resource’s state like GET and deletes the target resource’s URI like DELETE. – Géry Ogam Jul 09 '21 at 23:48
2

I find that Fielding 2002 is a useful reference here:

HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property (money, BTW, is considered property for the sake of this definition).

The method token "is the primary source of request semantics" (RFC 7231), and those semantics belong to the transfer of documents over a network domain.

Everything we are allowed to assume about a message is described by the standardized semantics; there is nothing resource specific involved, because HTTP satisfies the uniform interface constraint in this way: all resources understand HTTP messages the same way:

the standardized request methods in HTTP are not resource-specific, since uniform interfaces provide for better visibility and reuse in network-based systems [REST]. Once defined, a standardized method ought to have the same semantics when applied to any resource, though each resource determines for itself whether those semantics are implemented or allowed.


The special thing about POST is that it has practically no constraints on it at all:

POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”

So it could do just about anything (including, of course, doing nothing at all).


Which of these two interpretations is the correct one?

I would argue that changes to the representation(s) of the target resource are the intended effects of POST/PUT/PATCH, and anything else that happens is a side effect. See, for example, how RFC 7234 specifies invalidation.

  • Thanks. ‘there is nothing resource specific involved’ Except for POST, cf. RFC 7231, § 4.1: ‘Perform resource-specific processing on the request payload.’ – Géry Ogam Jul 08 '21 at 09:12
  • ‘I would argue that changes to the representation(s) of the target resource are the intended effects of POST/PUT/PATCH, and anything else that happens is a side effect.’ Interesting, but this seems to contradict RFC 7231, § 4.3.3: ‘POST is used for the following functions (among others): […] — Creating a new resource that has yet to be identified by the origin server;’ It does not look like a side effect to me. I think you meant that changes to the representations of any resource on the origin server are intended effects. – Géry Ogam Jul 08 '21 at 09:35