Search code examples
restapiputconventions

REST Update Best Practice: PUT collection/:id without id in body VS PUT collection/ with id included within body


I am trying to define conventions on PUT requests on a project I'm working on and I cannot decide which of these two options is the most appropriate, or if it is a matter of personal preference. I have seen multiple articles on REST best practices and it seems that the id is always implied as necessary as part of the url for PUT requests.

Goal: Update a resource via a REST API.

Options

  1. PUT collection/{id} - no id in the body
  2. PUT collection/ - no id in the URL, only in the body

Questions

  1. Which convention should I use?
  2. Why?
  3. Are there any generally applicable pros and cons for each option?

Solution

  • REST relies on the semantics of its transport layer, HTTP in most cases. HTTP at its heart is just a remote document management system that just takes care of sending files from one location to an other in a stateless manner. As Jim Webber pointed out, any business rules concluded are basically just a side-effect of the actual document management.

    As such, you should view your task firstly in the sense of a regular document management. You put a file up somewhere and replace any existing representation. This is what PUT actually means. An ID within a document is therefore not the best idea as long as it is not part of the actual document's content.

    Whether the URI contains a separate identifier or not is not of importance in a REST architecture. More formally, the whole URI is the identifier of a resource itself regardless whether you put some further ID into the URI or not. A URI neither should tell a client anything about the resource or its semantics nor about any hierarchy. Content type negotiation and link relations are there for.

    Fielding even stated that

    A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations. [Failure here implies that clients are assuming a resource structure due to out-of band information, such as a domain-specific standard, which is the data-oriented equivalent to RPC’s functional coupling]. (Source)

    The reason why many developers put IDs into their URIs is basically that on the server side they tokenize the URI and use respective tokens to perform a DB lookup on the respective segments. A reason why not to put i.e. productIDs into URIs is that when the ID changes, for whatever reason, the URI changes as a consequence event though the actual product remains perfectly the same. I.e. think of product A000123 that suddenly is referred to as P12300001 but nothing else changed. This could have happened due to a company merger or the like (have had such an incident in the past i.e.). In a REST architecture an URI such as /products/A000123 and /products/P12300001 refer to two different resources, and therefore two different products, even though they might return identical content. If instead of a product identifier a further, arbitrary UUID would have been used that leads to an internal mapping of that UUID to a productId the URI could have remained the same as basically the product also remained the same.

    I'd go so far to reframe your question to: "Does your client really need the ID?". In a perfect REST architecture a server would teach a client at any step of the process what the client is able and allowed to do. As REST is basically just a generalization of the concepts used on the Web, the whole design can be modeled as if the interaction should happen on the Web and then use the same concepts for application interactions. Think of an arbitrary client, human or machine-driven, that should order some item from Amazon i.e. The client asks Amazon for a list of products matching some search criteria, the server responds with a page containing links to more or less matching products a client can drill down further to learn the details of each product. If interested the client can add a product to its shopping cart by clicking a link. It actually doesn't care how the URI looks like, it just invoked it as some metadata (text or link relation name) stated that this will add the product to the cart. At no point the client is really interested in the actual product number, so why add it other than to give a client (human interactor) a possibility to use it for referral reasons in email interactions with the support or the like.

    In the end, whether you use IDs within URIs or the body payload, is your personal choice. Depending on your use-case exposing IDs to clients might not even be necessary as the whole interaction model used in REST (and on the Web) just use URIs to retrieve the next "page" of data and the hint on whether to use that URI is kept in metadata accompanying the URI, such as a summary text of the links content, as in the case of HTML links, or as part of link relation names that are either defined by media-types, by Web linking extensions (such as Dublin Core) or by a standardization authority.