In my previous post I established some guideline constraints to follow when designing a hypermedia API. Heavy emphasis on constraints, as the complexity we intentionally introduce now will greatly reduce the complexity of larger scaling and performance issues in time. In this post I will to discuss the first constraint, ‘The interface MUST embrace the underlying HTTP protocol’.
If you haven’t spent time on IANA or IEFT websites perusing the nearly endless supply of standards papers filled with normative and dry text, then you probably would consider yourself lucky. There is just an absolute mountain of current and proposed standards which fall under the HTTP umbrella, so you would be forgiven for not immediately rushing there to read everything related to HTTP. However, as an API designer you are responsible for the behavior of your design and you really should be familiar with the entirety of the basic specification of HTTP, as well as some of the more popular or useful additions.
I’ll step back and ask the obvious question, why is HTTP so important? A restful architecture is not a goal to be sought in its own right, but for the benefits the constraints offer to the overall performance and behavior of the application. By ensuring adherence to standards, you can expect a large range of clients to support your service immediately and for an extended service life without the burden of further technical intervention. Perhaps most importantly, adhering to standard functional definitions within the protocol will allow a service to fully leverage the benefits of a restful architecture. Presumably you are designing a service to send messages through HTTP, in that case as an example it would be beneficial to know when the protocol itself has a solution to a particularly difficult asynchronous application problem, like resource locking.
There are many reasons why asynchronous systems require the ability to lock a particular resource, be it exclusive access to physical or hardware resources, simultaneous editing, or even reserving items for a specific user’s purchase. There are two main approaches to locking ‘pessimistic’ and ‘optimistic’. Pessimistic locking requires the service to maintain the state of a resource as owned by a particular entity, but within a restful architecture we really really don’t want to add statefulness. This is not an ivory tower argument at all, the primary desire for statelessness in this case is the driven by the desire to allow caching. If a design were to introduce statefulness on any resource, it would be impossible for any caches to ever retain the resource as there would be no way to determine its current state. This leaves us the optimistic approach as the only viable option for a restful hypermedia API. Fortunately, the HTTP specification has a standard way to support optimistic locking.
To utilize optimistic locking, an HTTP service will provide metadata about a resource representation when responding to a request through the inclusion of an ETag header with a unique value for the resources state at the time of the response. When a consumer would like to modify the resource they will simply conduct the appropriate request along with supplying the previously returned ETag header value within the ‘If-Match’ header field and ‘return=minimal’ within the ‘Prefer’ header field. If the resource is unmodified, the service can perform the update and return a 204 status code, with a ‘Preference-Applied’ header value of ‘return’ and an empty body. However, if the resource has changed, the service can return a 409 conflict response while ignoring the request preference and returning the current representation, or with a ‘Location’ header with the resource URI and the ‘Preference-Applied’ header of ‘return’. It is important to note there is flexibility for implementation details within the protocol specifications for optimistic locking and most use cases should be covered. For applications intended to scale and effectively utilize a restful architecture caching is crucial to the performance of the system, and in the scenario presented above the resource is always cacheable.
This entire scenario is certainly more engaged than a simple request to a lock sub-URI on a resource, however a very large portion of a very difficult problem has already been handled through a standard, well known, and supported process.
Embracing the use of HTTP constructs to solve application concerns for your API, will allow you as the designer to focus on tasks which build value in your product and avoid extraneous boilerplate design.