api-json-server 1.1.0 → 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 +476 -126
- package/dist/behavior.js +12 -0
- package/dist/history/historyRecorder.js +66 -0
- package/dist/history/types.js +2 -0
- package/dist/index.js +29 -18
- package/dist/logger/customLogger.js +75 -0
- package/dist/logger/formatters.js +82 -0
- package/dist/logger/types.js +2 -0
- package/dist/registerEndpoints.js +20 -3
- package/dist/requestMatch.js +40 -1
- package/dist/server.js +62 -2
- package/dist/spec.js +38 -2
- package/package.json +6 -1
- package/src/behavior.ts +15 -1
- package/src/history/historyRecorder.ts +77 -0
- package/src/history/types.ts +25 -0
- package/src/index.ts +34 -21
- package/src/logger/customLogger.ts +85 -0
- package/src/logger/formatters.ts +74 -0
- package/src/logger/types.ts +30 -0
- package/src/registerEndpoints.ts +24 -6
- package/src/requestMatch.ts +43 -1
- package/src/server.ts +77 -4
- package/src/spec.ts +40 -2
- package/tests/cors.test.ts +128 -0
- package/tests/headers.test.ts +124 -0
- package/tests/helpers.ts +2 -2
- package/tests/history.test.ts +188 -0
- package/tests/matching.test.ts +109 -0
package/README.md
CHANGED
|
@@ -1,34 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# api-json-server
|
|
2
2
|
|
|
3
|
-
A mock API server driven by a JSON spec.
|
|
3
|
+
A powerful, feature-rich mock API server driven by a JSON spec. Designed for fast development, repeatable mock data, comprehensive testing, and clear API documentation.
|
|
4
4
|
|
|
5
5
|
## Highlights
|
|
6
6
|
|
|
7
|
-
- JSON spec
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
7
|
+
- **JSON-driven spec** - Define endpoints, responses, and matching rules in a simple JSON file
|
|
8
|
+
- **Advanced matching** - Match requests by query params, body, headers, and cookies
|
|
9
|
+
- **Custom headers** - Set response headers with template support
|
|
10
|
+
- **CORS configuration** - Global and per-endpoint CORS settings
|
|
11
|
+
- **Faker integration** - Generate realistic fake data (names, emails, phone numbers, companies, dates, etc.)
|
|
12
|
+
- **Response templating** - Use request data (params, query, body) in responses
|
|
13
|
+
- **Variants** - Define alternate responses based on match rules
|
|
14
|
+
- **Request history** - Record and inspect all incoming requests for debugging
|
|
15
|
+
- **Variable delays** - Simulate realistic network latency with random delay ranges
|
|
16
|
+
- **Error simulation** - Control error rates and responses
|
|
17
|
+
- **OpenAPI/Swagger** - Auto-generated OpenAPI docs with built-in Swagger UI
|
|
18
|
+
- **Hot reload** - Auto-reload when spec file changes (with `--watch`)
|
|
19
|
+
- **Beautiful logging** - Color-coded, readable console output
|
|
13
20
|
|
|
14
21
|
## Installation
|
|
15
22
|
|
|
16
|
-
```
|
|
23
|
+
```bash
|
|
17
24
|
npm install
|
|
18
25
|
```
|
|
19
26
|
|
|
20
27
|
## Quick Start
|
|
21
28
|
|
|
22
|
-
1) Create a spec file (
|
|
29
|
+
1) Create a spec file (`mock.spec.json`):
|
|
23
30
|
|
|
24
|
-
```
|
|
31
|
+
```json
|
|
25
32
|
{
|
|
26
33
|
"version": 1,
|
|
27
34
|
"settings": {
|
|
28
35
|
"delayMs": 0,
|
|
29
|
-
"errorRate": 0
|
|
30
|
-
"errorStatus": 500,
|
|
31
|
-
"errorResponse": { "error": "Mock error" }
|
|
36
|
+
"errorRate": 0
|
|
32
37
|
},
|
|
33
38
|
"endpoints": [
|
|
34
39
|
{
|
|
@@ -36,7 +41,9 @@ npm install
|
|
|
36
41
|
"path": "/users/:id",
|
|
37
42
|
"response": {
|
|
38
43
|
"id": "{{params.id}}",
|
|
39
|
-
"
|
|
44
|
+
"name": { "__faker": "person.fullName" },
|
|
45
|
+
"email": { "__faker": "internet.email" },
|
|
46
|
+
"avatar": { "__faker": "image.avatar" }
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
]
|
|
@@ -45,34 +52,62 @@ npm install
|
|
|
45
52
|
|
|
46
53
|
2) Start the server:
|
|
47
54
|
|
|
48
|
-
```
|
|
55
|
+
```bash
|
|
49
56
|
npm run dev -- serve --spec mock.spec.json
|
|
50
57
|
```
|
|
51
58
|
|
|
52
59
|
3) Test the endpoint:
|
|
53
60
|
|
|
61
|
+
```bash
|
|
62
|
+
curl "http://localhost:3000/users/42"
|
|
54
63
|
```
|
|
55
|
-
|
|
64
|
+
|
|
65
|
+
Response:
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"id": "42",
|
|
69
|
+
"name": "Jane Doe",
|
|
70
|
+
"email": "jane.doe@example.com",
|
|
71
|
+
"avatar": "https://cloudflare-ipfs.com/ipfs/..."
|
|
72
|
+
}
|
|
56
73
|
```
|
|
57
74
|
|
|
58
75
|
## CLI
|
|
59
76
|
|
|
60
|
-
```
|
|
61
|
-
mockserve serve
|
|
77
|
+
```bash
|
|
78
|
+
mockserve serve [options]
|
|
62
79
|
```
|
|
63
80
|
|
|
64
|
-
Options
|
|
81
|
+
### Options
|
|
65
82
|
|
|
66
|
-
- `--spec <path
|
|
67
|
-
- `--port <number
|
|
68
|
-
- `--watch` / `--no-watch
|
|
69
|
-
- `--base-url <url
|
|
83
|
+
- `--spec <path>` - Path to the JSON spec file (default: `mock.spec.json`)
|
|
84
|
+
- `--port <number>` - Port to run the server on (default: `3000`)
|
|
85
|
+
- `--watch` / `--no-watch` - Auto-reload when spec changes (default: enabled)
|
|
86
|
+
- `--base-url <url>` - Public base URL for OpenAPI servers[] (e.g., `https://api.example.com`)
|
|
87
|
+
- `--log-format <format>` - Log format: `pretty` or `json` (default: `pretty`)
|
|
88
|
+
- `--log-level <level>` - Log level: `trace`, `debug`, `info`, `warn`, `error`, `fatal` (default: `info`)
|
|
70
89
|
|
|
71
|
-
|
|
90
|
+
### Examples
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Start with custom port
|
|
94
|
+
mockserve serve --port 8080
|
|
72
95
|
|
|
73
|
-
|
|
96
|
+
# Use JSON logging format
|
|
97
|
+
mockserve serve --log-format json
|
|
74
98
|
|
|
99
|
+
# Disable auto-reload
|
|
100
|
+
mockserve serve --no-watch
|
|
101
|
+
|
|
102
|
+
# Set base URL for OpenAPI
|
|
103
|
+
mockserve serve --base-url https://api.mysite.com
|
|
75
104
|
```
|
|
105
|
+
|
|
106
|
+
## Spec Reference
|
|
107
|
+
|
|
108
|
+
The spec is validated by `mockserve.spec.schema.json`. It consists of:
|
|
109
|
+
|
|
110
|
+
```json
|
|
76
111
|
{
|
|
77
112
|
"version": 1,
|
|
78
113
|
"settings": { ... },
|
|
@@ -82,66 +117,120 @@ The spec is validated by `mockserve.spec.schema.json`. It is composed of:
|
|
|
82
117
|
|
|
83
118
|
### Settings
|
|
84
119
|
|
|
85
|
-
|
|
120
|
+
Global settings that apply to all endpoints unless overridden:
|
|
121
|
+
|
|
122
|
+
```json
|
|
86
123
|
{
|
|
87
124
|
"delayMs": 0,
|
|
88
125
|
"errorRate": 0,
|
|
89
126
|
"errorStatus": 500,
|
|
90
127
|
"errorResponse": { "error": "Mock error" },
|
|
91
|
-
"fakerSeed":
|
|
128
|
+
"fakerSeed": 12345,
|
|
129
|
+
"cors": {
|
|
130
|
+
"origin": "*",
|
|
131
|
+
"credentials": true
|
|
132
|
+
}
|
|
92
133
|
}
|
|
93
134
|
```
|
|
94
135
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
136
|
+
#### Settings Fields
|
|
137
|
+
|
|
138
|
+
- **`delayMs`** (number): Fixed delay in milliseconds before responding
|
|
139
|
+
- **`errorRate`** (number): Probability (0.0-1.0) of returning an error response
|
|
140
|
+
- **`errorStatus`** (number): HTTP status code for simulated errors
|
|
141
|
+
- **`errorResponse`** (any): Response body when error is triggered (supports templates)
|
|
142
|
+
- **`fakerSeed`** (number, optional): Seed for deterministic faker data generation
|
|
143
|
+
- **`cors`** (object, optional): CORS configuration
|
|
144
|
+
- `origin` (string | string[] | boolean): Allowed origins (`"*"`, `"https://example.com"`, or array)
|
|
145
|
+
- `credentials` (boolean): Allow credentials
|
|
146
|
+
- `methods` (string[]): Allowed HTTP methods
|
|
147
|
+
- `allowedHeaders` (string[]): Allowed request headers
|
|
148
|
+
- `exposedHeaders` (string[]): Exposed response headers
|
|
149
|
+
- `maxAge` (number): Preflight cache duration in seconds
|
|
100
150
|
|
|
101
151
|
### Endpoints
|
|
102
152
|
|
|
103
|
-
|
|
153
|
+
Each endpoint defines a route with its matching rules and response behavior:
|
|
154
|
+
|
|
155
|
+
```json
|
|
104
156
|
{
|
|
105
157
|
"method": "GET",
|
|
106
158
|
"path": "/users/:id",
|
|
107
|
-
"match": {
|
|
159
|
+
"match": {
|
|
160
|
+
"query": { "type": "premium" },
|
|
161
|
+
"headers": { "Authorization": "Bearer token123" },
|
|
162
|
+
"cookies": { "sessionId": "valid" }
|
|
163
|
+
},
|
|
108
164
|
"status": 200,
|
|
109
165
|
"response": { ... },
|
|
166
|
+
"headers": {
|
|
167
|
+
"X-Custom-Header": "value",
|
|
168
|
+
"Cache-Control": "no-cache"
|
|
169
|
+
},
|
|
170
|
+
"delay": { "min": 100, "max": 500 },
|
|
110
171
|
"delayMs": 0,
|
|
111
172
|
"errorRate": 0,
|
|
112
173
|
"errorStatus": 500,
|
|
113
|
-
"errorResponse": { "error": "
|
|
174
|
+
"errorResponse": { "error": "Not found" },
|
|
114
175
|
"variants": [ ... ]
|
|
115
176
|
}
|
|
116
177
|
```
|
|
117
178
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
179
|
+
#### Endpoint Fields
|
|
180
|
+
|
|
181
|
+
- **`method`** (string): HTTP method - `GET`, `POST`, `PUT`, `PATCH`, `DELETE`
|
|
182
|
+
- **`path`** (string): Route path with Fastify-style params (e.g., `/users/:id`)
|
|
183
|
+
- **`match`** (object, optional): Request matching rules (see [Match Rules](#match-rules))
|
|
184
|
+
- **`status`** (number): Default HTTP status code (default: `200`)
|
|
185
|
+
- **`response`** (any): Response body (supports templates)
|
|
186
|
+
- **`headers`** (object, optional): Custom response headers (supports templates in values)
|
|
187
|
+
- **`delay`** (object, optional): Variable delay range - `{ "min": 100, "max": 500 }`
|
|
188
|
+
- **`delayMs`** (number, optional): Fixed delay in milliseconds
|
|
189
|
+
- **`errorRate`** (number, optional): Error probability override
|
|
190
|
+
- **`errorStatus`** (number, optional): Error status override
|
|
191
|
+
- **`errorResponse`** (any, optional): Error response override
|
|
192
|
+
- **`variants`** (array, optional): Alternative responses with their own match rules
|
|
125
193
|
|
|
126
194
|
### Match Rules
|
|
127
195
|
|
|
128
|
-
|
|
196
|
+
Match rules determine if a request should be handled by an endpoint or variant. All specified match conditions must be satisfied.
|
|
197
|
+
|
|
198
|
+
```json
|
|
129
199
|
"match": {
|
|
130
|
-
"query": { "type": "premium" },
|
|
131
|
-
"body": { "
|
|
200
|
+
"query": { "type": "premium", "status": "active" },
|
|
201
|
+
"body": { "email": "test@example.com" },
|
|
202
|
+
"headers": { "Authorization": "Bearer secret" },
|
|
203
|
+
"cookies": { "sessionId": "abc123" }
|
|
132
204
|
}
|
|
133
205
|
```
|
|
134
206
|
|
|
135
|
-
|
|
207
|
+
#### Match Fields
|
|
208
|
+
|
|
209
|
+
- **`query`** (object): Exact match for query parameters (strings, numbers, booleans)
|
|
210
|
+
- **`body`** (object): Exact match for top-level body fields
|
|
211
|
+
- **`headers`** (object): Case-insensitive exact match for headers
|
|
212
|
+
- **`cookies`** (object): Exact match for cookies
|
|
213
|
+
|
|
214
|
+
If a request doesn't satisfy the match rules, the server returns `404` with:
|
|
215
|
+
```json
|
|
216
|
+
{ "error": "No matching mock for request" }
|
|
217
|
+
```
|
|
136
218
|
|
|
137
219
|
### Variants
|
|
138
220
|
|
|
139
|
-
Variants
|
|
221
|
+
Variants provide alternative responses based on match rules. The **first matching variant wins**. If no variant matches, the endpoint's base response is used.
|
|
140
222
|
|
|
141
|
-
```
|
|
223
|
+
```json
|
|
142
224
|
"variants": [
|
|
143
225
|
{
|
|
144
|
-
"name": "
|
|
226
|
+
"name": "admin user",
|
|
227
|
+
"match": { "body": { "role": "admin" } },
|
|
228
|
+
"status": 200,
|
|
229
|
+
"response": { "ok": true, "role": "admin", "permissions": ["*"] },
|
|
230
|
+
"headers": { "X-User-Role": "admin" }
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
"name": "invalid credentials",
|
|
145
234
|
"match": { "body": { "password": "wrong" } },
|
|
146
235
|
"status": 401,
|
|
147
236
|
"response": { "ok": false, "error": "Invalid credentials" }
|
|
@@ -149,138 +238,399 @@ Variants let you specify alternate responses based on match rules. The first mat
|
|
|
149
238
|
]
|
|
150
239
|
```
|
|
151
240
|
|
|
241
|
+
#### Variant Fields
|
|
242
|
+
|
|
243
|
+
- **`name`** (string, optional): Descriptive name for the variant
|
|
244
|
+
- **`match`** (object, optional): Match rules (same as endpoint-level)
|
|
245
|
+
- **`status`** (number, optional): HTTP status code
|
|
246
|
+
- **`response`** (any): Response body (supports templates)
|
|
247
|
+
- **`headers`** (object, optional): Custom response headers (overrides endpoint headers)
|
|
248
|
+
- **`delay`** / **`delayMs`** (optional): Delay overrides
|
|
249
|
+
- **`errorRate`**, **`errorStatus`**, **`errorResponse`** (optional): Error simulation overrides
|
|
250
|
+
|
|
152
251
|
### Response Templates
|
|
153
252
|
|
|
154
|
-
Responses support a
|
|
253
|
+
Responses support a powerful templating system combining static values, request data, faker directives, and array generation.
|
|
155
254
|
|
|
156
|
-
#### String
|
|
255
|
+
#### String Placeholders
|
|
157
256
|
|
|
158
|
-
-
|
|
159
|
-
- `{{query.type}}`
|
|
160
|
-
- `{{body.email}}`
|
|
257
|
+
Access request data using mustache-style placeholders:
|
|
161
258
|
|
|
162
|
-
```
|
|
259
|
+
```json
|
|
163
260
|
{
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
261
|
+
"userId": "{{params.id}}",
|
|
262
|
+
"searchType": "{{query.type}}",
|
|
263
|
+
"userEmail": "{{body.email}}"
|
|
167
264
|
}
|
|
168
265
|
```
|
|
169
266
|
|
|
170
|
-
|
|
267
|
+
**Available contexts:**
|
|
268
|
+
- `{{params.name}}` - Path parameters
|
|
269
|
+
- `{{query.key}}` - Query string parameters
|
|
270
|
+
- `{{body.field}}` - Request body fields (supports nested paths like `{{body.user.name}}`)
|
|
271
|
+
|
|
272
|
+
#### Faker Directives
|
|
171
273
|
|
|
172
|
-
|
|
274
|
+
Generate realistic fake data using any `@faker-js/faker` method:
|
|
173
275
|
|
|
276
|
+
**Simple syntax:**
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"name": { "__faker": "person.fullName" },
|
|
280
|
+
"email": { "__faker": "internet.email" },
|
|
281
|
+
"phone": { "__faker": "phone.number" },
|
|
282
|
+
"company": { "__faker": "company.name" },
|
|
283
|
+
"avatar": { "__faker": "image.avatar" },
|
|
284
|
+
"birthdate": { "__faker": "date.birthdate" },
|
|
285
|
+
"city": { "__faker": "location.city" }
|
|
286
|
+
}
|
|
174
287
|
```
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
288
|
+
|
|
289
|
+
**With arguments:**
|
|
290
|
+
```json
|
|
291
|
+
{
|
|
292
|
+
"randomString": { "__faker": { "method": "string.alpha", "args": [16] } },
|
|
293
|
+
"price": { "__faker": { "method": "number.float", "args": [{ "min": 10, "max": 100, "precision": 0.01 }] } }
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Deterministic output:**
|
|
298
|
+
Set `fakerSeed` in settings for consistent data across requests:
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"settings": {
|
|
302
|
+
"fakerSeed": 12345
|
|
303
|
+
}
|
|
304
|
+
}
|
|
178
305
|
```
|
|
179
306
|
|
|
180
|
-
#### Repeat
|
|
307
|
+
#### Repeat Directives
|
|
181
308
|
|
|
182
|
-
|
|
309
|
+
Generate arrays of items with random or fixed counts:
|
|
183
310
|
|
|
184
|
-
|
|
311
|
+
**Random count (min/max range):**
|
|
312
|
+
```json
|
|
185
313
|
{
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
|
|
189
|
-
|
|
314
|
+
"users": {
|
|
315
|
+
"__repeat": {
|
|
316
|
+
"min": 10,
|
|
317
|
+
"max": 15,
|
|
318
|
+
"template": {
|
|
319
|
+
"id": { "__faker": "string.uuid" },
|
|
320
|
+
"name": { "__faker": "person.fullName" },
|
|
321
|
+
"email": { "__faker": "internet.email" }
|
|
322
|
+
}
|
|
323
|
+
}
|
|
190
324
|
}
|
|
191
325
|
}
|
|
192
326
|
```
|
|
193
327
|
|
|
194
|
-
|
|
195
|
-
|
|
328
|
+
**Fixed count:**
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"tags": {
|
|
332
|
+
"__repeat": {
|
|
333
|
+
"count": 3,
|
|
334
|
+
"template": { "__faker": "lorem.word" }
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
196
338
|
```
|
|
339
|
+
|
|
340
|
+
**Combining templates:**
|
|
341
|
+
```json
|
|
197
342
|
{
|
|
198
|
-
"
|
|
199
|
-
|
|
200
|
-
"
|
|
343
|
+
"userId": "{{params.id}}",
|
|
344
|
+
"orders": {
|
|
345
|
+
"__repeat": {
|
|
346
|
+
"min": 5,
|
|
347
|
+
"max": 10,
|
|
348
|
+
"template": {
|
|
349
|
+
"orderId": { "__faker": "string.uuid" },
|
|
350
|
+
"amount": { "__faker": { "method": "number.float", "args": [{ "min": 10, "max": 1000, "precision": 0.01 }] } },
|
|
351
|
+
"status": { "__faker": { "method": "helpers.arrayElement", "args": [["pending", "shipped", "delivered"]] } }
|
|
352
|
+
}
|
|
353
|
+
}
|
|
201
354
|
}
|
|
202
355
|
}
|
|
203
356
|
```
|
|
204
357
|
|
|
205
|
-
|
|
358
|
+
## Advanced Features
|
|
206
359
|
|
|
207
|
-
|
|
208
|
-
- If `min` is omitted, it defaults to `0`.
|
|
209
|
-
- If `max` is missing, `min` is used.
|
|
210
|
-
- If `max < min`, the server returns a `500` error.
|
|
360
|
+
### Custom Response Headers
|
|
211
361
|
|
|
212
|
-
|
|
362
|
+
Set custom headers on responses, with support for templating:
|
|
213
363
|
|
|
364
|
+
```json
|
|
365
|
+
{
|
|
366
|
+
"method": "GET",
|
|
367
|
+
"path": "/api/data/:id",
|
|
368
|
+
"response": { "data": "value" },
|
|
369
|
+
"headers": {
|
|
370
|
+
"X-Resource-ID": "{{params.id}}",
|
|
371
|
+
"X-Request-Type": "{{query.type}}",
|
|
372
|
+
"Cache-Control": "max-age=3600",
|
|
373
|
+
"X-Custom-Header": "static-value"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
214
376
|
```
|
|
377
|
+
|
|
378
|
+
Variant headers override endpoint headers:
|
|
379
|
+
|
|
380
|
+
```json
|
|
215
381
|
{
|
|
216
382
|
"method": "GET",
|
|
217
|
-
"path": "/
|
|
218
|
-
"
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
"id": { "__faker": "string.uuid" },
|
|
225
|
-
"firstName": { "__faker": "person.firstName" },
|
|
226
|
-
"lastName": { "__faker": "person.lastName" },
|
|
227
|
-
"avatarUrl": { "__faker": "image.avatar" },
|
|
228
|
-
"phone": { "__faker": "phone.number" },
|
|
229
|
-
"email": { "__faker": "internet.email" },
|
|
230
|
-
"company": { "__faker": "company.name" },
|
|
231
|
-
"joinedAt": { "__faker": { "method": "date.recent", "args": [30] } }
|
|
232
|
-
}
|
|
233
|
-
}
|
|
383
|
+
"path": "/api/data",
|
|
384
|
+
"headers": { "X-Source": "base" },
|
|
385
|
+
"variants": [
|
|
386
|
+
{
|
|
387
|
+
"match": { "query": { "premium": "true" } },
|
|
388
|
+
"response": { "data": "premium" },
|
|
389
|
+
"headers": { "X-Source": "premium", "X-Tier": "gold" }
|
|
234
390
|
}
|
|
235
|
-
|
|
391
|
+
]
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Variable Delays
|
|
396
|
+
|
|
397
|
+
Simulate realistic network latency with random delay ranges:
|
|
398
|
+
|
|
399
|
+
```json
|
|
400
|
+
{
|
|
401
|
+
"method": "GET",
|
|
402
|
+
"path": "/api/slow",
|
|
403
|
+
"delay": { "min": 100, "max": 500 },
|
|
404
|
+
"response": { "ok": true }
|
|
236
405
|
}
|
|
237
406
|
```
|
|
238
407
|
|
|
239
|
-
|
|
408
|
+
The server will wait a random duration between 100ms and 500ms before responding.
|
|
409
|
+
|
|
410
|
+
### Request History
|
|
411
|
+
|
|
412
|
+
All requests are automatically recorded and can be inspected via the history endpoint:
|
|
413
|
+
|
|
414
|
+
**View all requests:**
|
|
415
|
+
```bash
|
|
416
|
+
GET /__history
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Filter by endpoint:**
|
|
420
|
+
```bash
|
|
421
|
+
GET /__history?endpoint=/api/users
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Filter by method:**
|
|
425
|
+
```bash
|
|
426
|
+
GET /__history?method=POST
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**Limit results:**
|
|
430
|
+
```bash
|
|
431
|
+
GET /__history?limit=10
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**Clear history:**
|
|
435
|
+
```bash
|
|
436
|
+
DELETE /__history
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**History entry format:**
|
|
440
|
+
```json
|
|
441
|
+
{
|
|
442
|
+
"entries": [
|
|
443
|
+
{
|
|
444
|
+
"id": "uuid",
|
|
445
|
+
"timestamp": "2026-01-18T14:30:00.000Z",
|
|
446
|
+
"method": "POST",
|
|
447
|
+
"url": "/api/users",
|
|
448
|
+
"path": "/api/users",
|
|
449
|
+
"query": {},
|
|
450
|
+
"headers": { "content-type": "application/json" },
|
|
451
|
+
"body": { "name": "John" },
|
|
452
|
+
"statusCode": 201,
|
|
453
|
+
"responseTime": 45
|
|
454
|
+
}
|
|
455
|
+
],
|
|
456
|
+
"total": 1
|
|
457
|
+
}
|
|
458
|
+
```
|
|
240
459
|
|
|
241
|
-
|
|
460
|
+
### CORS Configuration
|
|
242
461
|
|
|
243
|
-
|
|
244
|
-
- `GET /__openapi.yaml`
|
|
245
|
-
- `GET /docs`
|
|
246
|
-
- `GET /__spec`
|
|
247
|
-
- `GET /health`
|
|
462
|
+
Enable CORS globally or per-endpoint:
|
|
248
463
|
|
|
249
|
-
|
|
464
|
+
**Global CORS:**
|
|
465
|
+
```json
|
|
466
|
+
{
|
|
467
|
+
"settings": {
|
|
468
|
+
"cors": {
|
|
469
|
+
"origin": "*",
|
|
470
|
+
"credentials": true,
|
|
471
|
+
"methods": ["GET", "POST", "PUT", "DELETE"],
|
|
472
|
+
"allowedHeaders": ["Content-Type", "Authorization"]
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
250
477
|
|
|
251
|
-
|
|
478
|
+
**Per-endpoint CORS:**
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"method": "GET",
|
|
482
|
+
"path": "/api/public",
|
|
483
|
+
"cors": { "origin": "https://example.com" },
|
|
484
|
+
"response": { "data": "public" }
|
|
485
|
+
}
|
|
486
|
+
```
|
|
252
487
|
|
|
253
|
-
|
|
488
|
+
### Error Simulation
|
|
254
489
|
|
|
255
|
-
|
|
256
|
-
- `examples/auth-variants.json`
|
|
257
|
-
- `examples/users-faker.json`
|
|
258
|
-
- `examples/companies-nested.json`
|
|
259
|
-
- `examples/orders-and-matches.json`
|
|
490
|
+
Simulate random errors for reliability testing:
|
|
260
491
|
|
|
261
|
-
|
|
492
|
+
**Global error rate:**
|
|
493
|
+
```json
|
|
494
|
+
{
|
|
495
|
+
"settings": {
|
|
496
|
+
"errorRate": 0.1,
|
|
497
|
+
"errorStatus": 503,
|
|
498
|
+
"errorResponse": { "error": "Service temporarily unavailable" }
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
262
502
|
|
|
503
|
+
**Per-endpoint error rate:**
|
|
504
|
+
```json
|
|
505
|
+
{
|
|
506
|
+
"method": "GET",
|
|
507
|
+
"path": "/api/unstable",
|
|
508
|
+
"errorRate": 0.5,
|
|
509
|
+
"errorStatus": 500,
|
|
510
|
+
"errorResponse": { "error": "Internal server error" },
|
|
511
|
+
"response": { "ok": true }
|
|
512
|
+
}
|
|
263
513
|
```
|
|
264
|
-
import { buildServer } from "./dist/server.js";
|
|
265
|
-
import { loadSpecFromFile } from "./dist/loadSpec.js";
|
|
266
514
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
515
|
+
10% of requests will return the error response with the specified status code.
|
|
516
|
+
|
|
517
|
+
## Built-in Endpoints
|
|
518
|
+
|
|
519
|
+
mockserve provides several special endpoints for inspection and debugging:
|
|
520
|
+
|
|
521
|
+
- **`GET /health`** - Health check endpoint (returns `{ "ok": true }`)
|
|
522
|
+
- **`GET /__spec`** - View the loaded spec and metadata
|
|
523
|
+
- **`GET /__openapi.json`** - OpenAPI 3.0 specification in JSON format
|
|
524
|
+
- **`GET /__openapi.yaml`** - OpenAPI 3.0 specification in YAML format
|
|
525
|
+
- **`GET /docs`** - Interactive Swagger UI documentation
|
|
526
|
+
- **`GET /__history`** - View request history (supports filtering)
|
|
527
|
+
- **`DELETE /__history`** - Clear request history
|
|
528
|
+
|
|
529
|
+
## Examples
|
|
530
|
+
|
|
531
|
+
The `examples/` folder contains ready-to-use spec files demonstrating various features:
|
|
532
|
+
|
|
533
|
+
1. **`basic-crud.json`** - Simple CRUD operations with templating
|
|
534
|
+
2. **`auth-variants.json`** - Authentication with variants for different scenarios
|
|
535
|
+
3. **`users-faker.json`** - User list with faker-generated data and array ranges
|
|
536
|
+
4. **`companies-nested.json`** - Nested data structures with companies and employees
|
|
537
|
+
5. **`orders-and-matches.json`** - Complex matching with headers, cookies, and query params
|
|
538
|
+
|
|
539
|
+
Run any example:
|
|
540
|
+
```bash
|
|
541
|
+
mockserve serve --spec examples/users-faker.json
|
|
270
542
|
```
|
|
271
543
|
|
|
272
|
-
##
|
|
544
|
+
## Use Cases
|
|
545
|
+
|
|
546
|
+
### Development
|
|
547
|
+
|
|
548
|
+
Replace real backends during frontend development:
|
|
549
|
+
- No backend dependencies
|
|
550
|
+
- Instant API responses
|
|
551
|
+
- Test edge cases easily with variants
|
|
552
|
+
- Simulate network conditions with delays
|
|
553
|
+
|
|
554
|
+
### Testing
|
|
555
|
+
|
|
556
|
+
Create reliable, repeatable test environments:
|
|
557
|
+
- Deterministic data with `fakerSeed`
|
|
558
|
+
- Test error scenarios with `errorRate`
|
|
559
|
+
- Validate request/response flow with history
|
|
560
|
+
- Multiple test scenarios with variants
|
|
561
|
+
|
|
562
|
+
### Documentation
|
|
563
|
+
|
|
564
|
+
Auto-generated interactive API docs:
|
|
565
|
+
- OpenAPI/Swagger UI out of the box
|
|
566
|
+
- View all endpoints and response examples
|
|
567
|
+
- Test endpoints directly in the browser
|
|
568
|
+
- Export OpenAPI spec for tooling
|
|
569
|
+
|
|
570
|
+
### Demos & Prototypes
|
|
273
571
|
|
|
572
|
+
Quickly mock APIs for demos and prototypes:
|
|
573
|
+
- No coding required - just JSON
|
|
574
|
+
- Realistic data with faker
|
|
575
|
+
- Professional-looking APIs
|
|
576
|
+
- Easy to modify and iterate
|
|
577
|
+
|
|
578
|
+
## Schema Validation
|
|
579
|
+
|
|
580
|
+
Your spec file is validated against `mockserve.spec.schema.json`. Use JSON schema validation in your editor (VS Code, WebStorm, etc.) for autocomplete and error checking.
|
|
581
|
+
|
|
582
|
+
Add this to your spec file:
|
|
583
|
+
```json
|
|
584
|
+
{
|
|
585
|
+
"$schema": "./mockserve.spec.schema.json",
|
|
586
|
+
"version": 1,
|
|
587
|
+
...
|
|
588
|
+
}
|
|
274
589
|
```
|
|
590
|
+
|
|
591
|
+
## Development
|
|
592
|
+
|
|
593
|
+
```bash
|
|
594
|
+
# Install dependencies
|
|
595
|
+
npm install
|
|
596
|
+
|
|
597
|
+
# Run in development mode
|
|
598
|
+
npm run dev
|
|
599
|
+
|
|
600
|
+
# Build
|
|
601
|
+
npm run build
|
|
602
|
+
|
|
603
|
+
# Run tests
|
|
275
604
|
npm test
|
|
605
|
+
|
|
606
|
+
# Watch tests
|
|
607
|
+
npm run test:watch
|
|
608
|
+
|
|
609
|
+
# Generate JSON schema from Zod spec
|
|
610
|
+
npm run schema:build
|
|
276
611
|
```
|
|
277
612
|
|
|
278
|
-
##
|
|
613
|
+
## Architecture
|
|
279
614
|
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
-
|
|
615
|
+
- **TypeScript** - Fully typed codebase with strict mode
|
|
616
|
+
- **Fastify** - Fast, low-overhead web framework
|
|
617
|
+
- **Zod** - Runtime schema validation
|
|
618
|
+
- **Faker** - Realistic fake data generation
|
|
619
|
+
- **Pino** - High-performance logging
|
|
620
|
+
- **Vitest** - Fast unit testing
|
|
283
621
|
|
|
284
622
|
## License
|
|
285
623
|
|
|
286
624
|
ISC
|
|
625
|
+
|
|
626
|
+
## Contributing
|
|
627
|
+
|
|
628
|
+
Contributions are welcome! Please ensure:
|
|
629
|
+
- All tests pass (`npm test`)
|
|
630
|
+
- Code is properly typed (no `any`)
|
|
631
|
+
- Functions have JSDoc comments
|
|
632
|
+
- New features include tests and documentation
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
**Made with ❤️ for developers who need reliable mock APIs**
|