The vast majority of RESTful APIs follow a simple “request-response” message exchange pattern, but that pattern is often too limiting and is not sufficient to achieving robust and reliable application performance. We frequently get questions from customers asking: ‘How I design asynchronous APIs?’ and ‘How I design an API that allows for the concurrent modification of the same API resource without bringing the resource into inconsistent state?’. In this blog post, we present two approaches answering these questions using standard HTTP headers and status codes. Further, we provide RAML snippets that can serve as a starting point when designing such APIs.
Concurrent Modification of an API Resource
An application retrieves the state of an API resource, performs some task based on the data received, updates its local resource state, and then request the API to update the state of the resource on the server. Meanwhile, some other process or application has updated the state of the same resource which could result in a “corrupted” state. For example, an application reads the current balance of a customer’s loyalty points, adds some extra points and updates the balance, while some other process / application has already updated the balance.
Use an Optimistic Locking pattern. Optimistic locking is useful when there is a rare chance that different processes will “corrupt” each other’s data (in this case API shared resources). If the chance of corruption is really high, you might want to consider using Pessimistic locking. However, Pessimistic locking can introduce API performance issues, so you would only want to use it if it is needed.
Optimistic locking typically involves maintaining a version of the resource. An application reads the latest version of the resource, version ‘A,’ performs a local update of the resource state, and asks the API to update the state but only if the resource is still ‘A’. Once the resource is successfully updated, the API updates the version to ‘B’ so any other processes that attempt to modify the old version will fail to update the resource and will need to retry by reading the latest version, and applying changes to it before updating.
Fortunately, HTTP provides a standard mechanism to do that: Standard HTTP ETag and If-Match headers could be used to implement optimistic locking. Further, standard HTTP status code 412 Precondition Failed could be used to inform applications that it works with ‘out-of-date’ resource and should re-read the state (GET) before attempting to change it (PATCH or PUT).
The W3C’s HTTP standard (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) defines 412 status code as follows:
The pattern is illustrated in the diagram below:
Below, we provide a RAML snippet that illustrates an API that supports concurrent modification:
RESTful APIs use HTTP, which is a synchronous protocol. An application sends requests, blocks, and waits for a response. However, in some cases when the process has the potential to take a significantly long time (due to a slow backend system), this is not the desired behavior. Typical examples are mobile or modern Web application that provides reactive UI. Such an application can submit a request to create a new object, continue with some other task, and only show a notification when the customer object is created in the backend system and ready to consume.
Design the API so that an application can trigger asynchronous work. And only track the processing status from time to time. When the result is ready, the application should be able to retrieve it, or if the processing is not required any more, the application should be able to cancel it.
As in the previous case, this can be done using standard HTTP headers and status codes. For that reason, we use HTTP code 202 Accepted to inform the application that its request has been accepted for processing.
The W3C’s HTTP standard (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) defines 202 code as follows:
The W3C’s HTTP standard (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) defines 303 code as follows: The Location header is used to provide a link to such a status monitor. The application can use the URI provided in the Location header to poll the status of the processing. Once the processing is finished, the API provides the location of the actual result again using Location header but with a different HTTP status code, namely 303.
DELETE /resources/123/status request: In some cases, the application may want to cancel the processing. This could be achieved by sending
The following RAML snippet demonstrates the pattern:
Closing RAML Remarks
We hope these new patterns will help you develop new and better RAML specifications and improve the performance and reliability of your applications. Do you have an advanced pattern that you’d like to share or learn more about? Reach out to us at firstname.lastname@example.org to let us know.