Response processing hooks allow modification of cached data before storage. The hook system enables data transformation, compression, metadata addition, and custom processing of responses before they are cached.
Register hooks to process responses before caching.
/**
* Add a response processing hook
* @param name - Hook identifier (commonly 'onResponse')
* @param fn - Hook function that processes the cache value
*/
addHook(name: string, fn: Function): void;Usage Examples:
import CacheableRequest from "cacheable-request";
import { request } from "node:http";
const cacheableRequest = new CacheableRequest(request);
// Add hook for response decompression
cacheableRequest.addHook("onResponse", async (value, response) => {
if (response.headers["content-encoding"] === "gzip") {
const buffer = await gunzip(value.body);
value.body = buffer.toString();
}
return value;
});
// Add hook for metadata enrichment
cacheableRequest.addHook("onResponse", (value, response) => {
// Add remote address to cached data
if (response.connection) {
value.remoteAddress = response.connection.remoteAddress;
}
// Add timestamp
value.cachedAt = new Date().toISOString();
return value;
});
const cachedHttp = cacheableRequest.request();Remove previously registered hooks.
/**
* Remove a registered hook
* @param name - Hook identifier to remove
* @returns True if hook was removed, false if not found
*/
removeHook(name: string): boolean;Usage Examples:
// Remove specific hook
const removed = cacheableRequest.removeHook("onResponse");
if (removed) {
console.log("Hook removed successfully");
} else {
console.log("Hook not found");
}Get reference to registered hook functions.
/**
* Get a registered hook function
* @param name - Hook identifier
* @returns Hook function or undefined if not found
*/
getHook(name: string): Function | undefined;Usage Examples:
// Check if hook exists
const hook = cacheableRequest.getHook("onResponse");
if (hook) {
console.log("onResponse hook is registered");
} else {
console.log("No onResponse hook found");
}Execute hooks manually (primarily used internally).
/**
* Execute a registered hook
* @param name - Hook identifier
* @param value - Cache value to process
* @param response - HTTP response object
* @returns Promise resolving to processed cache value
*/
runHook(name: string, value: CacheValue, response: any): Promise<CacheValue>;Usage Examples:
// Manually run hook (advanced usage)
const processedValue = await cacheableRequest.runHook("onResponse", cacheValue, response);Standard hook function patterns and expected signatures.
/**
* Standard response hook function signature
* @param value - Cache value to be stored
* @param response - HTTP response object
* @returns Modified cache value or Promise<CacheValue>
*/
type ResponseHook = (
value: CacheValue,
response: any
) => CacheValue | Promise<CacheValue>;Common Hook Patterns:
// Synchronous transformation
cacheableRequest.addHook("onResponse", (value, response) => {
// Transform body to JSON
if (typeof value.body === "string") {
try {
value.parsedBody = JSON.parse(value.body);
} catch (e) {
value.parseError = e.message;
}
}
return value;
});
// Asynchronous processing
cacheableRequest.addHook("onResponse", async (value, response) => {
// Compress response body
if (value.body.length > 1024) {
value.body = await compress(value.body);
value.compressed = true;
}
return value;
});
// Conditional processing
cacheableRequest.addHook("onResponse", (value, response) => {
// Only process successful responses
if (value.statusCode >= 200 && value.statusCode < 300) {
value.success = true;
value.processedAt = Date.now();
}
return value;
});Managing multiple hooks for complex processing pipelines.
interface HookChain {
/** Hooks are executed in the order they were added */
executionOrder: "sequential";
/** Each hook receives the output of the previous hook */
chaining: "piped";
}Usage Examples:
const cacheableRequest = new CacheableRequest(request);
// Hook 1: Parse JSON
cacheableRequest.addHook("onResponse", (value, response) => {
if (response.headers["content-type"]?.includes("application/json")) {
try {
value.json = JSON.parse(value.body.toString());
} catch (e) {
value.jsonError = e.message;
}
}
return value;
});
// Hook 2: Extract metadata
cacheableRequest.addHook("onResponse", (value, response) => {
if (value.json) {
value.metadata = {
recordCount: Array.isArray(value.json) ? value.json.length : 1,
hasData: Boolean(value.json),
};
}
return value;
});
// Hook 3: Compress large responses
cacheableRequest.addHook("onResponse", async (value, response) => {
if (value.body.length > 10000) {
value.body = await compress(value.body);
value.compressed = true;
}
return value;
});Proper error handling within hook functions.
type SafeHook = (value: CacheValue, response: any) => CacheValue | Promise<CacheValue>;Usage Examples:
// Error handling in hooks
cacheableRequest.addHook("onResponse", async (value, response) => {
try {
// Potentially failing operation
value.processed = await riskyOperation(value.body);
} catch (error) {
// Don't throw - just add error info
value.processingError = error.message;
console.warn("Hook processing failed:", error);
}
// Always return the value
return value;
});
// Conditional hook execution
cacheableRequest.addHook("onResponse", (value, response) => {
// Only process if certain conditions are met
if (value.statusCode === 200 && value.body) {
try {
value.enhanced = enhanceData(value.body);
} catch (error) {
value.enhancementError = error.message;
}
}
return value;
});interface CacheValue {
url: string;
statusCode: number;
body: Buffer | string;
cachePolicy: CachePolicyObject;
/** Hook functions can add any additional properties */
[key: string]: any;
}
type HookFunction = (
value: CacheValue,
response: any
) => CacheValue | Promise<CacheValue>;