Mimic Node.js HTTP Response Stream Properties
The `mimic-response` library is a utility designed to replicate properties and events from a Node.js `http.IncomingMessage` (an HTTP response stream) onto any generic Node.js stream. This is particularly useful in scenarios like proxying or transforming HTTP responses where the downstream stream needs to inherit metadata such as `statusCode`, `statusMessage`, and `headers` without copying the actual data payload. The current stable version is `4.0.0`. Historically, new major versions have been released roughly annually, typically coinciding with updated Node.js LTS requirements and ecosystem shifts like the move to pure ESM. Its key differentiator lies in its specific focus on mirroring *response stream properties* rather than content, providing a lightweight way to maintain HTTP context across stream transformations. It stands apart from related tools like `mimic-fn` (for functions) or broader stream cloning utilities by targeting the specific metadata of an HTTP response.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/node_modules/mimic-response/index.js from /your/project/index.js not supported.
cause Attempting to use `require()` to import `mimic-response` version 4.0.0 or higher in a CommonJS module.fixRefactor your consuming code to use `import` syntax within an ES module (by adding `"type": "module"` to `package.json` or using `.mjs` files), or use dynamic `import` like `const mimicResponse = (await import('mimic-response')).default;`. -
SyntaxError: Cannot use import statement outside a module
cause Using `import` syntax for `mimic-response` v4.0.0+ in a Node.js file that is not treated as an ES module.fixAdd `"type": "module"` to your `package.json` file, or rename your file to have a `.mjs` extension. Ensure your Node.js version is compatible (Node.js 12.20.0 or higher for v4.x). -
TypeError: Cannot read properties of undefined (reading 'statusCode') OR TypeError: mimicResponse is not a function
cause Incorrectly attempting to import `mimicResponse` as a named export (e.g., `import { mimicResponse } from 'mimic-response';`) instead of a default export.fixUse the correct default import syntax: `import mimicResponse from 'mimic-response';`. -
TypeError: myStream.destroy is not a function (when calling myStream.destroy())
cause Calling `destroy()` on a target stream (`myStream`) without it having a custom `destroy` method, specifically when you intend for the destroy call to be propagated to the source stream.fixImplement a `destroy` method in the constructor options of your target stream (e.g., `new PassThroughStream({ destroy(error, callback) { /* ... */ } })`) that also calls `from.destroy(error)` if propagation is desired.
Warnings
- breaking Version 4.0.0 of `mimic-response` is a pure ESM package. This means it can only be imported using `import` statements in ES modules, or dynamically with `await import()` in CommonJS. Direct `require()` calls are no longer supported.
- breaking Version 4.0.0 increased the minimum Node.js requirement to `^12.20.0 || ^14.13.1 || >=16.0.0`.
- breaking Version 3.0.0 increased the minimum Node.js requirement to Node.js 10.
- breaking Version 2.0.0 increased the minimum Node.js requirement to Node.js 8.
- gotcha The `destroy(error)` function of the source stream (`from`) is not automatically proxied to the target stream (`to`). If you need to propagate destroy calls, you must manually implement the `destroy` method on your target stream and call `from.destroy(error)` within it.
Install
-
npm install mimic-response -
yarn add mimic-response -
pnpm add mimic-response
Imports
- mimicResponse
const mimicResponse = require('mimic-response');import mimicResponse from 'mimic-response';
- mimicResponse
import { mimicResponse } from 'mimic-response';import mimicResponse from 'mimic-response';
- mimicResponse (type)
import type { mimicResponse } from 'mimic-response';import type mimicResponse from 'mimic-response';
Quickstart
import { PassThrough as PassThroughStream } from 'node:stream';
import mimicResponse from 'mimic-response';
function getHttpResponseStream() {
// Simulate an http.IncomingMessage with relevant properties
const response = new PassThroughStream();
Object.defineProperty(response, 'statusCode', { value: 200, configurable: true });
Object.defineProperty(response, 'statusMessage', { value: 'OK', configurable: true });
Object.defineProperty(response, 'headers', { value: { 'content-type': 'application/json' }, configurable: true });
Object.defineProperty(response, 'rawHeaders', { value: ['Content-Type', 'application/json'], configurable: true });
Object.defineProperty(response, 'trailers', { value: {}, configurable: true });
Object.defineProperty(response, 'rawTrailers', { value: [], configurable: true });
return response;
}
const responseStream = getHttpResponseStream();
const myStream = new PassThroughStream();
mimicResponse(responseStream, myStream);
console.log('Original status code:', responseStream.statusCode);
console.log('Mimicked status code:', myStream.statusCode);
// Demonstrating the 'destroy' caveat
const myStreamWithDestroy = new PassThroughStream({
destroy(error, callback) {
console.log('myStreamWithDestroy destroy called with error:', error ? error.message : 'none');
responseStream.destroy(error); // Ensure the source stream's destroy is also called
callback(error);
}
});
mimicResponse(responseStream, myStreamWithDestroy);
// Simulate an error causing the stream to destroy
myStreamWithDestroy.destroy(new Error('Simulated stream error'));