Express Response Modification Middleware
raw JSON →The `modify-response-middleware` package provides an Express middleware designed to intercept and transform HTTP response bodies before they are sent to the client. It transparently handles various compression encodings like Gzip, Brotli, Deflate, and Br, allowing developers to modify response data regardless of its original compression status. As of version 1.1.0, it supports both uncompressed and compressed payloads, offering options to disable caching (`noCache`). This middleware is particularly useful for injecting data, sanitizing output, or performing last-minute transformations on API responses. Its release cadence appears stable but infrequent, typical for a focused utility. A key differentiator is its built-in handling of common compression algorithms, abstracting away the complexities of decompression and re-compression during modification.
Common errors
error SyntaxError: Unexpected token < in JSON at position 0 ↓
res.get('Content-Type') within your modifyRes callback to ensure it's application/json. Add a try...catch block around JSON.parse() to handle non-JSON or malformed responses gracefully. error TypeError: content.toString is not a function ↓
if (content && Buffer.isBuffer(content)) before calling content.toString() or attempting to process content. For empty responses, content might legitimately be null or an empty buffer, in which case it should be returned as is. error (Client-side) ERR_CONTENT_LENGTH_MISMATCH or truncated responses ↓
Content-Length header. If issues persist, ensure the middleware or your callback removes res.removeHeader('Content-Length') or explicitly sets res.setHeader('Content-Length', Buffer.byteLength(newContent)) for non-compressed content. Warnings
breaking Middleware order is critical. `modify-response-middleware` must be applied *before* any route handlers or other middleware that send responses (e.g., `res.send()`, `res.json()`). Placing it after these handlers will result in it never being invoked for those responses, as headers might have already been sent. ↓
gotcha Modifying response bodies, especially after decompression and before re-compression, can introduce performance overhead. For very large responses or high-traffic applications, this can significantly impact server throughput and latency due to CPU usage for (de)compression and memory for buffering. ↓
gotcha When modifying response content, `Content-Length` and `ETag` headers can become invalid. The `noCache: true` option helps mitigate `ETag` issues by setting `Cache-Control: no-cache`, but if `Content-Length` is present and incorrect, it can lead to client-side issues or truncated responses. The middleware attempts to handle this, but explicit verification is sometimes needed. ↓
gotcha The callback function provided to `modifyRes` expects `content` to be a `Buffer`. If your modification logic assumes a specific content type (e.g., JSON) and attempts parsing without proper checks, it can throw errors for other content types (e.g., HTML, plain text, images). ↓
Install
npm install modify-response-middleware yarn add modify-response-middleware pnpm add modify-response-middleware Imports
- modifyRes wrong
const modifyRes = require('modify-response-middleware')correctimport modifyRes from 'modify-response-middleware' - Buffer wrong
import { Buffer } from 'buffer'correctimport { Buffer } from 'node:buffer'
Quickstart
import express from 'express';
import modifyRes from 'modify-response-middleware';
const app = express();
app.use(express.json()); // Ensure JSON body parsing for incoming requests if needed
// Apply the modification middleware early in the stack
app.use(modifyRes((content, req, res) => {
if (content && res.get('Content-Type')?.includes('application/json')) {
try {
const data = JSON.parse(content.toString());
// Example: Modify the age property of the JSON response
data.age = (data.age || 0) + 2;
data.message = 'Response modified by middleware!';
return Buffer.from(JSON.stringify(data));
} catch (e) {
console.error('Failed to parse or modify JSON content:', e);
// Return original content if modification fails
return content;
}
}
// Always return content, even if no modification occurred or type didn't match
return content;
}, {
noCache: true, // Prevents 304 Not Modified responses, useful for dynamic content
}));
app.get('/user', (req, res) => {
res.json({
name: 'Tom',
age: 18,
status: 'active'
});
});
app.get('/html', (req, res) => {
res.send('<h1>Hello, World!</h1><p>This is an HTML response.</p>');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
console.log(`Test with: curl http://localhost:${PORT}/user`);
console.log(`Test with: curl http://localhost:${PORT}/html`);
});