@jaredwray/mockhttp 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,18 @@ A simple HTTP server that can be used to mock HTTP responses for testing purpose
21
21
  * Auto detect the port that is not in use
22
22
  * Maintained and updated regularly!
23
23
 
24
+ # Table of Contents
25
+ - [Deploy via Docker](#deploy-via-docker)
26
+ - [Deploy via Docker Compose](#deploy-via-docker-compose)
27
+ - [Deploy via NodeJS](#deploy-via-nodejs)
28
+ - [Response Injection (Tap Feature)](#response-injection-tap-feature)
29
+ - [Rate Limiting](#rate-limiting)
30
+ - [Logging](#logging)
31
+ - [API Reference](#api-reference)
32
+ - [About mockhttp.org](#about-mockhttporg)
33
+ - [Contributing](#contributing)
34
+ - [License](#license)
35
+
24
36
  # Deploy via Docker
25
37
  ```bash
26
38
  docker run -d -p 3000:3000 jaredwray/mockhttp
@@ -60,7 +72,7 @@ then run `mockhttp` in your code.
60
72
  import { mockhttp } from '@jaredwray/mockhttp';
61
73
  await mockhttp.start(); // start the server
62
74
  const response = await fetch('http://localhost:3000/get');
63
- console.log(reaponse);
75
+ console.log(response);
64
76
  await mockhttp.stop(); // stop the server
65
77
  ```
66
78
 
@@ -247,6 +259,184 @@ const tap = mock.taps.inject(
247
259
  );
248
260
  ```
249
261
 
262
+ # Rate Limiting
263
+
264
+ MockHttp supports rate limiting using [@fastify/rate-limit](https://github.com/fastify/fastify-rate-limit). Rate limiting is **enabled by default** at **1000 requests per minute** with **localhost (127.0.0.1 and ::1) excluded** from rate limiting.
265
+
266
+ ## Default Rate Limiting
267
+
268
+ By default, MockHttp applies the following rate limit:
269
+ - **1000 requests per minute** per IP address
270
+ - **Localhost is excluded** - requests from 127.0.0.1 and ::1 bypass rate limiting (ideal for local development and testing)
271
+
272
+ ```javascript
273
+ import { MockHttp } from '@jaredwray/mockhttp';
274
+
275
+ const mock = new MockHttp();
276
+ await mock.start();
277
+ // Rate limiting is active (1000 req/min) except for localhost
278
+ ```
279
+
280
+ ## Customizing Rate Limiting
281
+
282
+ To customize rate limiting, pass a `rateLimit` configuration object when creating your MockHttp instance:
283
+
284
+ ```javascript
285
+ import { MockHttp } from '@jaredwray/mockhttp';
286
+
287
+ const mock = new MockHttp({
288
+ rateLimit: {
289
+ max: 100, // Maximum 100 requests
290
+ timeWindow: '1 minute' // Per 1 minute window
291
+ }
292
+ });
293
+
294
+ await mock.start();
295
+ ```
296
+
297
+ ## Common Configuration Options
298
+
299
+ The `rateLimit` option accepts all [@fastify/rate-limit options](https://github.com/fastify/fastify-rate-limit#options):
300
+
301
+ ### Basic Rate Limiting
302
+
303
+ ```javascript
304
+ // Limit to 50 requests per minute
305
+ const mock = new MockHttp({
306
+ rateLimit: {
307
+ max: 50,
308
+ timeWindow: '1 minute'
309
+ }
310
+ });
311
+ ```
312
+
313
+ ### Stricter Limits with Custom Error Response
314
+
315
+ ```javascript
316
+ const mock = new MockHttp({
317
+ rateLimit: {
318
+ max: 30,
319
+ timeWindow: 60000, // 1 minute in milliseconds
320
+ errorResponseBuilder: (req, context) => ({
321
+ statusCode: 429,
322
+ error: 'Too Many Requests',
323
+ message: `Rate limit exceeded. Try again in ${context.after}`
324
+ })
325
+ }
326
+ });
327
+ ```
328
+
329
+ ### Allow List (Exclude Specific IPs)
330
+
331
+ ```javascript
332
+ const mock = new MockHttp({
333
+ rateLimit: {
334
+ max: 100,
335
+ timeWindow: '1 minute',
336
+ allowList: ['127.0.0.1', '192.168.1.100'] // These IPs bypass rate limiting
337
+ }
338
+ });
339
+ ```
340
+
341
+ ### Custom Key Generator (Rate Limit by Header)
342
+
343
+ ```javascript
344
+ const mock = new MockHttp({
345
+ rateLimit: {
346
+ max: 100,
347
+ timeWindow: '1 minute',
348
+ keyGenerator: (request) => {
349
+ // Rate limit by API key instead of IP
350
+ return request.headers['x-api-key'] || request.ip;
351
+ }
352
+ }
353
+ });
354
+ ```
355
+
356
+ ### Advanced Configuration
357
+
358
+ ```javascript
359
+ const mock = new MockHttp({
360
+ rateLimit: {
361
+ global: true, // Apply to all routes
362
+ max: 100, // Max requests
363
+ timeWindow: '1 minute', // Time window
364
+ cache: 10000, // Cache size for tracking clients
365
+ skipOnError: false, // Don't skip on storage errors
366
+ ban: 10, // Ban after 10 rate limit violations
367
+ continueExceeding: false, // Don't reset window on each request
368
+ enableDraftSpec: true, // Use IETF draft spec headers
369
+ addHeaders: { // Customize rate limit headers
370
+ 'x-ratelimit-limit': true,
371
+ 'x-ratelimit-remaining': true,
372
+ 'x-ratelimit-reset': true
373
+ }
374
+ }
375
+ });
376
+ ```
377
+
378
+ ## Disabling Rate Limiting
379
+
380
+ To disable rate limiting completely, set the `rateLimit` option to `false`:
381
+
382
+ ```javascript
383
+ const mock = new MockHttp({
384
+ rateLimit: false // Completely disable rate limiting
385
+ });
386
+
387
+ await mock.start();
388
+ // No rate limiting is applied to any requests
389
+ ```
390
+
391
+ **Note:** To change rate limiting settings after the server has started, you must restart the server:
392
+
393
+ ```javascript
394
+ const mock = new MockHttp();
395
+ await mock.start(); // Starts with default rate limiting
396
+
397
+ // To change or disable rate limiting:
398
+ await mock.close();
399
+ mock.rateLimit = undefined; // or set new options
400
+ await mock.start(); // Restarts with new settings
401
+ ```
402
+
403
+ ## Available Options
404
+
405
+ | Option | Type | Default | Description |
406
+ |--------|------|---------|-------------|
407
+ | `max` | number \| function | `1000` | Maximum requests per time window |
408
+ | `timeWindow` | number \| string | `60000` | Duration of rate limit window (milliseconds or string like '1 minute') |
409
+ | `cache` | number | `5000` | LRU cache size for tracking clients |
410
+ | `allowList` | array \| function | `[]` | IPs or function to exclude from rate limiting |
411
+ | `keyGenerator` | function | IP-based | Function to generate unique client identifier |
412
+ | `errorResponseBuilder` | function | Default 429 | Custom error response function |
413
+ | `skipOnError` | boolean | `false` | Skip rate limiting if storage errors occur |
414
+ | `ban` | number | `-1` | Ban client after N violations (disabled by default) |
415
+ | `continueExceeding` | boolean | `false` | Renew time window on each request while limited |
416
+ | `enableDraftSpec` | boolean | `false` | Use IETF draft specification headers |
417
+
418
+ For the complete list of options, see the [@fastify/rate-limit documentation](https://github.com/fastify/fastify-rate-limit#options).
419
+
420
+ # Logging
421
+
422
+ MockHttp uses [Pino](https://github.com/pinojs/pino) for logging via Fastify's built-in logger. Logging is **enabled by default** but can be disabled when needed.
423
+
424
+ ## Disabling Logging
425
+
426
+ ```javascript
427
+ import { MockHttp } from '@jaredwray/mockhttp';
428
+
429
+ const mock = new MockHttp({ logging: false });
430
+ await mock.start();
431
+ // Server runs silently without any log output
432
+ ```
433
+
434
+ You can also disable logging via the `LOGGING` environment variable:
435
+
436
+ ```bash
437
+ LOGGING=false node your-app.js
438
+ ```
439
+
250
440
  # API Reference
251
441
 
252
442
  ## MockHttp Class
@@ -264,7 +454,19 @@ new MockHttp(options?)
264
454
  - `autoDetectPort?`: boolean - Auto-detect next available port if in use (default: true)
265
455
  - `helmet?`: boolean - Use Helmet for security headers (default: true)
266
456
  - `apiDocs?`: boolean - Enable Swagger API documentation (default: true)
457
+ - `rateLimit?`: RateLimitPluginOptions - Configure rate limiting (default: 1000 req/min, localhost excluded)
458
+ - `logging?`: boolean - Enable logging (default: true)
267
459
  - `httpBin?`: HttpBinOptions - Configure which httpbin routes to enable
460
+ - `httpMethods?`: boolean - Enable HTTP method routes (default: true)
461
+ - `redirects?`: boolean - Enable redirect routes (default: true)
462
+ - `requestInspection?`: boolean - Enable request inspection routes (default: true)
463
+ - `responseInspection?`: boolean - Enable response inspection routes (default: true)
464
+ - `statusCodes?`: boolean - Enable status code routes (default: true)
465
+ - `responseFormats?`: boolean - Enable response format routes (default: true)
466
+ - `cookies?`: boolean - Enable cookie routes (default: true)
467
+ - `anything?`: boolean - Enable anything routes (default: true)
468
+ - `auth?`: boolean - Enable authentication routes (default: true)
469
+ - `images?`: boolean - Enable image routes (default: true)
268
470
  - `hookOptions?`: HookifiedOptions - Hookified options
269
471
 
270
472
  ### Properties
@@ -274,6 +476,8 @@ new MockHttp(options?)
274
476
  - `autoDetectPort`: boolean - Get/set auto-detect port behavior
275
477
  - `helmet`: boolean - Get/set Helmet security headers
276
478
  - `apiDocs`: boolean - Get/set API documentation
479
+ - `logging`: boolean - Get/set logging enabled state
480
+ - `rateLimit`: RateLimitPluginOptions | undefined - Get/set rate limiting options
277
481
  - `httpBin`: HttpBinOptions - Get/set httpbin route options
278
482
  - `server`: FastifyInstance - Get/set the Fastify server instance
279
483
  - `taps`: TapManager - Get/set the TapManager instance
@@ -334,6 +538,10 @@ Register "anything" catch-all routes.
334
538
 
335
539
  Register authentication routes (basic, bearer, digest, hidden-basic).
336
540
 
541
+ #### `async registerImageRoutes(fastifyInstance?)`
542
+
543
+ Register image routes (jpeg, png, svg, webp) with content negotiation support.
544
+
337
545
  ## Taps (Response Injection)
338
546
 
339
547
  Access the TapManager via `mockHttp.taps` to inject custom responses.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { RateLimitPluginOptions } from '@fastify/rate-limit';
1
2
  import { FastifyRequest, FastifyInstance } from 'fastify';
2
3
  import { Hookified, HookifiedOptions } from 'hookified';
3
4
 
@@ -130,6 +131,7 @@ type HttpBinOptions = {
130
131
  cookies?: boolean;
131
132
  anything?: boolean;
132
133
  auth?: boolean;
134
+ images?: boolean;
133
135
  };
134
136
  type MockHttpOptions = {
135
137
  /**
@@ -157,10 +159,19 @@ type MockHttpOptions = {
157
159
  * Whether to use Swagger UI. Defaults to true.
158
160
  */
159
161
  httpBin?: HttpBinOptions;
162
+ /**
163
+ * Rate limiting options. Defaults to 1000 requests per minute (localhost excluded).
164
+ * Set to undefined to disable rate limiting, or provide custom options to configure.
165
+ */
166
+ rateLimit?: boolean | RateLimitPluginOptions;
160
167
  /**
161
168
  * Hookified options.
162
169
  */
163
170
  hookOptions?: HookifiedOptions;
171
+ /**
172
+ * Whether to enable logging. Defaults to true.
173
+ */
174
+ logging?: boolean;
164
175
  };
165
176
  declare class MockHttp extends Hookified {
166
177
  private _port;
@@ -168,7 +179,9 @@ declare class MockHttp extends Hookified {
168
179
  private _autoDetectPort;
169
180
  private _helmet;
170
181
  private _apiDocs;
182
+ private _logging;
171
183
  private _httpBin;
184
+ private _rateLimit?;
172
185
  private _server;
173
186
  private _taps;
174
187
  constructor(options?: MockHttpOptions);
@@ -222,6 +235,16 @@ declare class MockHttp extends Hookified {
222
235
  * @default true
223
236
  */
224
237
  set apiDocs(apiDocs: boolean);
238
+ /**
239
+ * Whether to enable logging. Defaults to true.
240
+ * @default true
241
+ */
242
+ get logging(): boolean;
243
+ /**
244
+ * Whether to enable logging. Defaults to true.
245
+ * @default true
246
+ */
247
+ set logging(logging: boolean);
225
248
  /**
226
249
  * HTTP Bin options. Defaults to all enabled.
227
250
  */
@@ -230,6 +253,20 @@ declare class MockHttp extends Hookified {
230
253
  * HTTP Bin options. Defaults to all enabled.
231
254
  */
232
255
  set httpBin(httpBinary: HttpBinOptions);
256
+ /**
257
+ * Rate limiting options. Defaults to 1000 requests per minute (localhost excluded).
258
+ * Set to undefined to disable rate limiting, or provide custom options to configure.
259
+ * @default { max: 1000, timeWindow: "1 minute", allowList: ["127.0.0.1", "::1"] }
260
+ */
261
+ get rateLimit(): RateLimitPluginOptions | undefined;
262
+ /**
263
+ * Rate limiting options. Defaults to 1000 requests per minute (localhost excluded).
264
+ * Set to undefined to disable rate limiting, or provide custom options to configure.
265
+ *
266
+ * Note: Changing this property requires restarting the server (close() then start()) for changes to take effect.
267
+ * @default { max: 1000, timeWindow: "1 minute", allowList: ["127.0.0.1", "::1"] }
268
+ */
269
+ set rateLimit(rateLimit: RateLimitPluginOptions | undefined);
233
270
  /**
234
271
  * The Fastify server instance.
235
272
  */
@@ -305,6 +342,11 @@ declare class MockHttp extends Hookified {
305
342
  * @param fastifyInstance - the server instance to register the routes on.
306
343
  */
307
344
  registerAuthRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
345
+ /**
346
+ * Register the image routes.
347
+ * @param fastifyInstance - the server instance to register the routes on.
348
+ */
349
+ registerImageRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
308
350
  }
309
351
 
310
352
  declare const start: () => Promise<MockHttp>;