tamper - Response Body Middleware
raw JSON →tamper is a Node.js middleware designed for intercepting and modifying HTTP response bodies before they are sent to the client. It provides a simple API for Connect/Express-compatible applications, allowing developers to inspect request and response headers and conditionally apply transformations to the response body. The current stable version, 1.1.0, indicates a mature but largely feature-complete codebase with infrequent updates. Its primary differentiation lies in its focused scope of response body manipulation, offering a callback-based or Promise-based mechanism for transformations. It's particularly useful for tasks like injecting scripts, performing server-side content rewrites, or debugging response payloads without directly altering original handlers. It ships with TypeScript types, enhancing developer experience for type-safe applications.
Common errors
error ReferenceError: require is not defined in ES module scope ↓
tamper is a CommonJS module, you need to use import tamper from 'tamper' with a bundler that handles CJS-to-ESM conversion, or switch your file to CommonJS (.cjs or package.json "type": "commonjs"). error Error: Cannot find module 'tamper' ↓
npm install tamper or yarn add tamper to install the package. Verify the package is listed in node_modules and that require('tamper') is spelled correctly. error RangeError: Invalid array length ↓
tamper logic explicitly checks res.getHeader('Content-Type') to only process text/html, text/plain, or other expected string-based content types. Place tamper before compression middleware. Warnings
gotcha Modifying response bodies implies buffering the entire response in memory. For very large responses, this can lead to significant memory consumption and increased latency. Consider alternatives for streaming modifications if performance is critical for large files. ↓
gotcha When modifying a response body, the `Content-Length` HTTP header (if present) becomes invalid. Clients relying on this header might receive truncated or incomplete data. `tamper` attempts to handle this, but manual verification is recommended. ↓
gotcha If compression middleware (e.g., `compression`) is used *after* `tamper`, `tamper` will receive the uncompressed body, but the `Content-Length` issue still applies. If `compression` is used *before* `tamper`, `tamper` will receive and attempt to modify the compressed binary body, which will result in corrupted output. ↓
breaking `tamper` v1.x is a CommonJS module. Attempting to import it using ES module syntax (`import tamper from 'tamper';`) will fail in Node.js environments unless specific experimental flags or bundler configurations are used. This can be a breaking change when migrating older CJS applications to a modern ESM-first setup. ↓
Install
npm install tamper yarn add tamper pnpm add tamper Imports
- tamper wrong
import tamper from 'tamper';correctconst tamper = require('tamper'); - Middleware wrong
import type { TamperMiddleware } from 'tamper';correctimport { Request, Response, NextFunction } from 'express'; const tamper = require('tamper'); // To type the result of tamper() type TamperHandler = (req: Request, res: Response, next: NextFunction) => void;
Quickstart
import express, { Request, Response, NextFunction } from 'express';
import tamper from 'tamper'; // This would actually be 'const tamper = require("tamper")' for CJS
// For demonstration, let's pretend tamper supports ESM or use require syntax
const app = express();
app.use(tamper(function(req: Request, res: Response) {
// Only modify HTML responses
if (res.getHeader('Content-Type')?.toString().includes('text/html')) {
console.log(`Tampering with HTML response for ${req.url}`);
// Return a function to capture and modify the body
return function(body: string) {
// Replace all occurrences of 'foo' with 'bar'
// Or inject a script tag for client-side analytics
return body.replace(/foo/g, 'bar').replace('</body>', '<script>console.log("Body tampered!")</script></body>');
};
}
// Return a falsy value to continue without body modification
return;
}));
app.get('/', (req, res) => {
res.status(200).set('Content-Type', 'text/html').send('<html><body><h1>Hello foo world!</h1></body></html>');
});
app.get('/json', (req, res) => {
res.json({ message: 'This is JSON' });
});
const PORT = process.env.PORT ?? 3000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
console.log('Try visiting http://localhost:3000 and http://localhost:3000/json');
});