HTTP Request Recording and Playback Proxy
Yakbak is a Node.js library for recording and playing back HTTP interactions, serving as a "VCR" for your HTTP clients during testing and development. It operates as a reverse proxy: requests are forwarded to a target host, and their responses are recorded ("taped") to disk. Subsequent identical requests are then played back from these recorded tapes instead of hitting the remote server, enabling consistent and fast test runs. Tapes are stored as `.js` files (Node modules), allowing for standalone replay servers. The current stable version is 5.0.1. While there isn't a strict release cadence, updates appear to be driven by dependency maintenance and Node.js version compatibility. Key differentiators include its reverse proxy approach, the flexible storage of tapes as re-executable Node modules, and its seamless integration with Node's native `http` module or popular frameworks like Express.
Common errors
-
Error: file is required Usage: yakbak <file>
cause The `yakbak` command-line utility was executed without specifying the path to a recorded tape file as an argument.fixProvide the path to a recorded tape file that you wish to serve, for example: `yakbak ./tapes/your-tape-id.js`.
Warnings
- breaking Yakbak v5.0.0 dropped support for Node.js versions older than 10. Users on unsupported Node.js runtimes will encounter errors or unexpected behavior.
- gotcha The `dirname` option is mandatory when initializing `yakbak(host, options)`. Failure to provide a valid path will result in errors during operation when the library attempts to save or load recorded tapes.
- gotcha When the `noRecord` option is set to `true`, Yakbak will return a 404 Not Found error for any request where a matching tape does not already exist on disk. It will *not* proxy the request to the target host and record it.
Install
-
npm install yakbak -
yarn add yakbak -
pnpm add yakbak
Imports
- yakbak
const yakbak = require('yakbak').yakbak;import yakbak from 'yakbak';
- yakbak (CommonJS)
import yakbak from 'yakbak';
const yakbak = require('yakbak'); - Tape handler
const tape = require('./tapes/1117f3d81490d441d826dd2fb26470f9.js');
Quickstart
const http = require('http');
const path = require('path');
const fs = require('fs');
const yakbak = require('yakbak');
// Ensure the tapes directory exists
const tapesDir = path.join(__dirname, 'tapes');
if (!fs.existsSync(tapesDir)) {
fs.mkdirSync(tapesDir, { recursive: true });
}
// Create a yakbak handler for a dummy API endpoint
// We'll proxy to httpbin.org for demonstration
const handler = yakbak('https://httpbin.org', {
dirname: tapesDir
});
// Create an HTTP server that uses the yakbak handler
const proxyServer = http.createServer((req, res) => {
console.log(`Proxying request for: ${req.url}`);
handler(req, res); // Yakbak handles the request (record or playback)
});
const PORT = 3000;
proxyServer.listen(PORT, () => {
console.log(`Yakbak proxy server listening on http://localhost:${PORT}`);
// Example client request to the yakbak proxy
// This request will either be recorded or played back
http.get(`http://localhost:${PORT}/get?foo=bar`, (response) => {
let data = '';
response.on('data', (chunk) => (data += chunk));
response.on('end', () => {
console.log('\n--- Client received response from Yakbak proxy ---');
console.log(`Status: ${response.statusCode}`);
console.log('Body:', JSON.parse(data));
proxyServer.close(() => {
console.log('Proxy server closed.');
// Clean up tapes for repeated runs, if not desired to persist
fs.rmdirSync(tapesDir, { recursive: true });
});
});
}).on('error', (err) => {
console.error('Client request error:', err);
proxyServer.close();
fs.rmdirSync(tapesDir, { recursive: true });
});
});