Beyond Basic REST - Deep Dive into ETags and If-Match
Optimizing Concurrency Handling with ETag and If-Match
** This post is updated on 26-07-2024
While the underlying structure of RESTful APIs is crucial, the true magic lies in the details – specifically, HTTP headers. Among these unsung heroes, ETag and If-Match/If-None-Match stand out for their ability to optimize performance and ensure data consistency.
In this post, we’ll delve into these powerful headers and explore how to leverage them effectively within NestJS. By mastering their implementation, we’ll equip the RESTful API to handle concurrent transactions with grace and ensure robust data management.
Understanding HTTP Headers
Before diving into ETags and If-Match/If-None-Match, it’s essential to understand HTTP headers.
HTTP headers are key-value pairs that carry additional information with an HTTP request or response. They provide context about the request or response, enabling efficient communication between the client and server.
Types of HTTP Headers
- General Headers: Apply to both requests and responses, providing general information about the message.
- Examples: Cache-Control
- Request Headers: Convey information about the client and the request being made.
- Examples: Accept, Authorization, User-Agent
- Response Headers: Provide information about the response, including content type, status, and caching directives.
- Examples: Content-Type, Content-Length, Set-Cookie
- Entity Headers: Describe the characteristics of the message body.
- Examples: Etag, Content-Encoding
What is ETag and If-Match
An Entity Tag, or ETag
, is used to identify a specific version of a resource uniquely. It is a hash or identifier associated with the state of a resource on the server. There are two types of Etag: weak and strong . The weak Etag allows for flexibility in representing semantically equivalent content. Strong Etag is suitable for the resource representation that is byte-for-byte identical for all users.
When a client requests a resource, the server attaches an ETag to the response. Subsequent requests from the client can include this ETag in the If-None-Match
header. The header is used to determine whether the resource has changed, the server responds with a “304 Not Modified
” status if the resource has not changed, reducing unnecessary data transfer and enhancing performance.
On the other hand, the If-Match
header is employed for optimistic concurrency control. It can ensure that an operation, such as an update or deletion, is only performed if the provided ETag
matches the current state of the resource on the server.
The significance of ETag
and If-Match
lies in their ability to prevent conflicting updates. In scenarios where multiple clients modify the same resource concurrently, these headers act as safeguards. ETag
enables efficient caching and reduces unnecessary data transfers while If-Match
ensuring that updates occur only when the client possesses the latest resource version. Together, they contribute to a more resilient interaction between clients and servers in RESTful APIs.
How to create and return an Etag
To generate an ETag
in NestJS using the [etag](https://github.com/jshttp/etag)
library, follow the below steps to install and import the library.
1 | // install it |
Then, we can generate an Etag
with a one-line call.
1 | const data = // your data here; |
Please note that the etag function only accepts string, buffer, or steams. We can’t pass objects or arrays directly, but a workaround exists below.
1 | const arrayData = [1, 2, 3]; |
Then, we can return the Etag
in the response header for a GET request.
1 | 'etag') ( |
Please note that we need to set the passthrough
option to true in the @Res({ passthrough: true })
decorator because injecting the @Res
will disable the default route handling by default.
Use Etag for effective Caching
One of the primary purposes of Etag
is caching. After calling the GET the first time, the client retrieves the Etag
in response, and then the subsequent requests can include this ETag
in the If-None-Match
header.
an example of if-none-match header in the request
If-None-Match: “bfc13a64729c4290ef5b2c2730249c88ca92d82d”
In the GET endpoint, add a check to compare the Etag
in If-None-Match
to determine whether a resource has been modified. We can return a 304 Not Modified response if the resource has not been changed.
1 | () |
Upon receiving the response with a 304 status, most modern browsers will fetch the resource from the local cache.
Use If-Match for Optimistic Concurrency Control
The If-Match
header is commonly used to facilitate optimistic concurrency control. What exactly is optimistic concurrency control?
Optimistic concurrency control is a strategy for managing multiple users attempting to modify the same piece of data simultaneously. Instead of locking the data and preventing others from making changes, optimistic concurrency assumes that conflicts are rare. Users can make changes independently, but before saving their modifications, the system checks if someone else has modified the data. If no changes conflict, the modifications are accepted; otherwise, the system prompts users to resolve the inconsistency.
Now, let’s see how to implement it in a PUT request.
1 | ':id') ( |
When a client sends a request to update a resource, the client includes the current ETag
of the resource in the If-Match
header. The server then checks if the provided ETag
matches the current state of the resource. If there’s a match, the update proceeds; otherwise, the server returns a “412 Precondition Failed
” status, indicating that another party has modified the resource.
The same approach can be used not only for PUT but also applicable to DELETE and PATCH requests.
What is difference between If-Match and If-None-Match
It is worth highlighting that If-Match
and If-None-Match
headers serve different purposes in the context of ETags
. Here’s a breakdown of their differences:
If-Match
Header
- It is used in requests to operate (e.g., update or delete) only if the provided
ETag
matches the current ETag of the resource on the server. - If the ETag matches, the operation is performed; otherwise, the server responds with a “412 Precondition Failed” status, indicating that another party modified the resource.
If-None-Match
Header
- It is used in requests to get a resource only if its ETag does not match the specified ETag(s).
- If the ETag matches, the server responds with a “304 Not Modified” status, indicating that the client’s cached version is still valid and there’s no need to transfer the resource again.
Summary
We explored the use of ETag and If-Match/If-None-Match headers. Using ETag with If-Match is a good practice for optimistic concurrency control. I hope this post has been helpful and that you’ve learned something new.
- Title: Beyond Basic REST - Deep Dive into ETags and If-Match
- Author: Sunny Sun
- Created at : 2024-03-05 00:00:00
- Updated at : 2024-07-27 15:08:53
- Link: http://coffeethinkcode.com/2024/03/05/beyond-basic-rest-deep-dive-etags-if-match/
- License: This work is licensed under CC BY-NC-SA 4.0.