Search code examples
httpputrestful-urlidempotent

Can http PUT modify the identifier?


In a Restful API:

PUT /product/{id}

Could the above http request, specify a different id in its body, so that to actually change the id of original record (assume the id is changable technically in the underling storage).

This seems to vialotes the Restful's idempotent rule for PUT.
But I am not sure about it, (even after searching via Google).

Any idea?


Solution

  • First and foremost, PUT is specified as:

    The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response. However, there is no guarantee that such a state change will be observable, since the target resource might be acted upon by other user agents in parallel, or might be subject to dynamic processing by the origin server, before any subsequent GET is received.

    By that definition "moving" a resource via PUT would violate the HTTP specification and as such REST, as the resource can't be retrieved via the same URI again, in case the URI should reflect the updated ID as well and no redirection is implemented. You are, however, free to use POST instead as here the payload is processed according to the resource's own semantics. Note that the change of the actual payload (the resource's state) isn't the actual problem, but the "replacement" of the URI would be, according to the spec.

    According to Fielding a resource is anything that can be named, like a certain document, a picture of an event that happened somewhere. Even a collection of other resources can be a resource itself. Fielding described a resource to be a mapping of time to a set of entities or values, which are equivalent. A value here may be a resource representation and/or resource identifiers. This means that a resource therefore is allowed to change over time. This behavior can be seen on a daily basis on the Web, i.e.

    In chapter 6.2 of the dissertation, Fielding talks about how REST applies to URIs.

    ... The definition of resource in REST is based on a simple premise: identifiers should change as infrequently as possible. Because the Web uses embedded identifiers rather than link servers, authors need an identifier that closely matches the semantics they intend by a hypermedia reference, allowing the reference to remain static even though the result of accessing that reference may change over time. REST accomplishes this by defining a resource to be the semantics of what the author intends to identify, rather than the value corresponding to those semantics at the time the reference is created. It is then left to the author to ensure that the identifier chosen for a reference does indeed identify the intended semantics. ...

    ... a resource can have many identifiers. In other words, there may exist two or more different URI that have equivalent semantics when used to access a server. It is also possible to have two URI that result in the same mechanism being used upon access to the server, and yet those URI identify two different resources because they don't mean the same thing.

    Semantics are a by-product of the act of assigning resource identifiers and populating those resources with representations. At no time whatsoever do the server or client software need to know or understand the meaning of a URI. ...

    While the content of a resource may change over time and as such the resource may use a different internal record ID (or the like), it is questionable whether the product actually changes (that much) just by giving it a different ID? In such a case it would probably be beneficial not to use the internal product ID within the URI itself but instead use an arbitrary value, such as a UUID in general. As clients shouldn't interpret or attempt to extract meaning from URIs, the characters in the URI are actually not that important in a REST architecture. Instead meaningful link-relations should be used instead to allow a client to determine the use of the URI.

    In a REST architecture, clients only work upon the negotiated (and thus supported) representations and therefore only on information provided by the server. In case a server requires input from a client it will provide the client with a form representation that the client knows how to act upon. On the Web products usually can be listed or searched via a dedicated elements such as links or search fields where the affordance, basically what you can do with that element, is clear. In such a system a list of products, presented on its own result page, may use customized link-relation names to hint the clients about the concrete product and attach a link a client only invokes if it is interested on interacting with that particular product. A client therefore hasn't to parse or interpret the URI but only has to know the meaning or use-case of the link-relation itself. The same interaction model and affordance concept should be used in a REST architecture as well.

    A (temporary) redirect to the new product "page" could be setup to allow clients, that still have an older version of the product URI, to still interact with that resource and also get updated about the new location. This will basically allow any HTTP operation to work as before. Especially due to caching certain clients might not be aware of the location change yet as they might get served with a still-fresh-enough representation by their local or intermediary cache. As such a redirect would be a reasonable choice.

    In summary:

    • using PUT to basically "move" resources around and generating different target URIs therefore violates the HTTP spec, and thus REST. A fallback to POST should be used instead.
    • avoid to include the product's internal ID into the URI, to decouple the identifier of the product from the actual URI to allow to reuse the URI even when the internal identifier changes. This might require a mapping on the server side which product is exposed on which URI. This goes well with Mike Amundsen who claimed that Your data model is not your object model is not your resource model is not your affordance model.
    • implement a (temporary) redirect from the old URI to the new URI to allow older clients to still interact with the product