ETag-based HTTP Response Caching
request-etag is a small, in-memory module designed for ETag-based HTTP response caching. It manages the `If-None-Match` header automatically for subsequent GET requests to the same URL, retrieving cached bodies for 304 Not Modified responses. The package currently leverages `lru-cache` for its underlying caching mechanism, which can be configured with options like `max` size. Crucially, `request-etag` defaults to using the `request` library as its HTTP client, which has been officially deprecated and is no longer maintained since February 11th, 2020. While an alternative HTTP client can be injected, it *must* adhere to the `request` library's API signature. The package's current stable version is 2.0.3, but its reliance on a deprecated core dependency suggests a slow or inactive release cadence, limiting its suitability for new projects. Its primary differentiator is its focused, lightweight approach to abstracting ETag caching logic.
Common errors
-
My request is not being cached, even though I expect it to be.
cause The HTTP method used for the request was not GET. `request-etag` only caches GET requests.fixEnsure that the HTTP request you are attempting to cache is a GET request. -
My request is not being cached, even though I expect it to be.
cause The server response did not include an ETag header, which is essential for `request-etag` to identify and manage cached resources.fixCheck the server's configuration to confirm that `ETag` headers are being sent for the resources you wish to cache. -
My request is not being cached, even though I expect it to be.
cause The outbound request included a non-empty `Cookie` header, which `request-etag` interprets as a reason not to cache the response.fixRemove any `Cookie` headers from requests that you intend for `request-etag` to cache. If cookies are necessary, `request-etag` cannot cache that specific response. -
TypeError: Cannot read properties of undefined (reading 'call') or similar when using a custom HTTP client.
cause The custom HTTP client provided to the `ETagRequest` constructor does not precisely match the expected API signature of the deprecated `request` library.fixVerify that your custom HTTP client's function signature and callback arguments (specifically `(error, response, body)`) perfectly mimic those of the `request` library, as `request-etag` relies on this specific interface.
Warnings
- breaking Critical security vulnerability and maintenance risk due to reliance on the deprecated 'request' library. The 'request' package is no longer maintained, meaning it won't receive security updates or bug fixes.
- gotcha The module is explicitly designed for GET requests only; other HTTP methods (POST, PUT, DELETE, etc.) will not be cached.
- gotcha Caching will not occur if the HTTP response lacks an ETag header, or if the request includes a non-empty `Cookie` header.
- gotcha The underlying HTTP client provided to `ETagRequest` must strictly adhere to the API signature of the deprecated `request` library.
- gotcha Responses with bodies larger than the configured `max` cache size (set in `cacheConfig`) will not be stored in the cache.
Install
-
npm install request-etag -
yarn add request-etag -
pnpm add request-etag
Imports
- ETagRequest
import ETagRequest from 'request-etag';
const ETagRequest = require('request-etag'); - ETagRequest constructor
const eTagRequest = new ETagRequest(cacheConfig);
const eTagRequest = new ETagRequest(cacheConfig, modernHttpClient);
- Callback signature
eTagRequest(url, function (error, response, body) { /* ... */ });
Quickstart
const ETagRequest = require('request-etag');
const request = require('request'); // In a real application, use a modern HTTP client compatible with 'request' API
// Configure the cache, e.g., max 10MB to store response bodies
const cacheConfig = {
max: 10 * 1024 * 1024 // 10MB limit for the cache
};
// Initialize ETagRequest. In a production environment, 'request' should be replaced
// with a modern, maintained HTTP client that provides the same API signature.
const eTagRequest = new ETagRequest(cacheConfig, request);
// Define a target URL for caching
const urlToCache = 'https://www.google.com/';
console.log('--- First request (expecting 200 OK) ---');
eTagRequest(urlToCache, function (error, response, body) {
if (error) {
console.error('Initial request failed:', error);
return;
}
if (response.statusCode === 200) {
console.log(`Status: ${response.statusCode} - Body retrieved from actual HTTP response.`);
// console.log(body.substring(0, 100) + '...'); // Log a snippet of the body
} else {
console.log(`Initial request unexpected status: ${response.statusCode}`);
}
console.log('\n--- Second request (expecting 304 Not Modified from cache) ---');
eTagRequest(urlToCache, function (error2, response2, body2) {
if (error2) {
console.error('Second request failed:', error2);
return;
}
if (response2.statusCode === 304) {
console.log(`Status: ${response2.statusCode} - Body retrieved from internal cache.`);
// console.log(body2.substring(0, 100) + '...'); // Log a snippet of the cached body
} else if (response2.statusCode === 200) {
console.log(`Status: ${response2.statusCode} - Unexpected 200 on second request, cache might be bypassed.`);
} else {
console.log(`Second request unexpected status: ${response2.statusCode}`);
}
});
});