@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 +209 -1
- package/dist/index.d.ts +42 -0
- package/dist/index.js +3214 -29
- package/package.json +30 -25
- package/public/logo.jpg +0 -0
- package/public/logo.png +0 -0
- package/public/logo.webp +0 -0
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(
|
|
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>;
|