Resource Archetypes and PUT and POST Methods

One question that crops up frequently about RESTful API design is the differences between the POST and PUT methods. Both seem to accomplish similar objectives with vastly different requirements and processes. Why then are there two methods? And what are resource archetypes?

Like chess, each method has unique advantages and disadvantages when used.

You can catch up on different data sending methods for the PowerShell language in the “Sending Data Using PowerShell and RESTful API Methods” article. However, I wanted to go a bit deeper into what is happening when you use these methods and why they exist in a separate post.

Let’s dig in!

Resource Archetypes

To begin, I’ll need to talk more about the types of RESTful API resource archetypes that are available: Document, Collection, Store, and Controller. When you address various RESTful API endpoints, you’re dealing with one of these four archetypes. There are exceptions to this – such as hybrids – but let’s keep it simple for now.

For simplicity sake, I’ll be using the context of a virtualized environment and Rubrik’s Cloud Data Management software with the related RESTful API. This means we’ll be tackling virtual machines and their associated snapshots with backup data.

The four archetypes in more detail:

  • Document: An object containing fields and values that describe a resource. It is often compared to a database entry. This could be an object that represents a virtual machine or a snapshot and can also include links to other related resources.
  • Collection: This is a group of objects that is managed by the RESTful API server and referred to as “server managed.” Imagine an endpoint that contains information on all of your virtual machines or snapshots; it’s not mutable, but you can ask the endpoint to add or remove objects from the Collection.
  • Store: Similar to a Collection, except that it is “user managed” and allows for you to determine what gets added, removed, or modified. When you create a new object in a Store, the URI returned is user defined. Imagine adding metadata, such as a tag, to a virtual machine’s Store.
  • Controller: This is an endpoint that performs processing. If the API server is able to perform actions, such as powering on a virtual machine or creating a zero space clone, these will typically be mapped to a Controller resource.

These terms and their deeper meaning is typically something an API architect would keep in mind while designing the structure and available resources. However, it doesn’t hurt to know more about this as an operator, either.

Armed with this knowledge, we can dive deeper into the PUT and POST methods.

PUT Method (and some PATCH)

PUT is intended to be used with a Store. Since it is user managed, you are putting resources inside of the Store. The rules are fairly straight forward, as described in RFC 2616, in that you are either creating a new resource if one does not exist, or updating a resource if it already does exist.

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.

RFC 2616

Because of this behavior, this method is also idempotent. PUT’ing data into a resource multiple times yields the same end results: the resource will exist with the data given via the API request. It also means that resources addressed by a PUT request must also be mutable (changeable).

This is somewhat more understandable when looking at the URI. For example:

PUT /vmware/vcenter/{id}

Because of the URI path, I can be fairly confident that nothing else beyond the resource in the URI is being touched because I am addressing a specific resource in the Store. A PUT request is narrowly defined to the resource specified in the URI, which is the desired design.

The one frustration you may experience with PUT is having to send over the entire set of fields and values each time. If you don’t already know the values, you’ll need to start with a GET, make a change to one or more fields, and then send back the entirety of the data with a PUT. If this isn’t your cup of tea, the PATCH method is an alternative design. Check to see if the API you are working with supports this method since not all of them do. It’s also worth noting that the same endpoint can support multiple methods with completely different intentions; don’t just assume that PUT and PATCH will follow the same logic on the same resource.

Finally, it’s common to see a PUT request sent to a URI that ends with a user defined value or an id value such as {id} when viewed by Swagger or other tools.

An example PUT request to a Store resource.

POST Method

POST is used with server managed resource archetypes: Collections and Controllers. With a POST request, the server is being asked to generate a new resource within a Collection or to execute the action(s) available from a Controller. Interestingly enough, the term generally comes from the concept of newsgroups and that you would “post” news to the group. Isn’t language fun?

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.

The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI. The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate to a database.

RFC 2616

The use of POST is not idempotent. Each request will generate a new resource within the Collection or execute a new process by the Controller (often asynchronously from my experience).

An example POST request to a Collection resource.
An example POST request to a Controller resource.

Thoughts

There are definitely some ups and downs to all of the various methods used to create or update resource data held behind a RESTful API. The major considerations include the resource archetype and the desire for idempotent requests.

Keep in mind that a PUT request will always require you to send over a full payload of all fields and values held by a resource, while the PATCH method allows for you to pick and choose only the bits that are being modified.

POST, on the other hand, is not idempotent and should require a bit of thought when coding against endpoints to avoid the risk of generating more resources than desired, such as with payment requests.