0
# Response Actions
1
2
Comprehensive response generation system supporting fixed responses, dynamic callbacks, file streaming, request forwarding, and connection manipulation for simulating various server behaviors.
3
4
## Capabilities
5
6
### Fixed Responses
7
8
Simple static responses with predefined status, body, and headers.
9
10
```typescript { .api }
11
interface RequestRuleBuilder {
12
/**
13
* Send a fixed response with specified status code, body, and optional headers/trailers.
14
* Body can be string, Buffer, or object (automatically JSON-serialized).
15
*/
16
thenReply(
17
status: number,
18
data?: string | Buffer | object,
19
headers?: Headers,
20
trailers?: Trailers
21
): Promise<MockedEndpoint>;
22
23
/**
24
* Send a fixed response with specified status code, custom status message, body, and optional headers/trailers.
25
*/
26
thenReply(
27
status: number,
28
statusMessage: string,
29
data: string | Buffer,
30
headers?: Headers,
31
trailers?: Trailers
32
): Promise<MockedEndpoint>;
33
34
/**
35
* Send a JSON response with specified status code and object data.
36
* Automatically sets Content-Type to application/json.
37
*/
38
thenJson(
39
status: number,
40
data: object,
41
headers?: Headers
42
): Promise<MockedEndpoint>;
43
44
/**
45
* Send response from a file with specified status and optional headers.
46
*/
47
thenFromFile(
48
status: number,
49
filePath: string,
50
headers?: Headers
51
): Promise<MockedEndpoint>;
52
53
/**
54
* Send response from a file with specified status, custom status message, and optional headers.
55
*/
56
thenFromFile(
57
status: number,
58
statusMessage: string,
59
filePath: string,
60
headers?: Headers
61
): Promise<MockedEndpoint>;
62
}
63
64
interface Headers {
65
[key: string]: undefined | string | string[];
66
}
67
68
interface Trailers {
69
[key: string]: undefined | string | string[];
70
}
71
```
72
73
**Usage Examples:**
74
75
```typescript
76
import { getLocal } from "mockttp";
77
78
const mockServer = getLocal();
79
await mockServer.start();
80
81
// Simple text response
82
await mockServer.forGet("/api/hello")
83
.thenReply(200, "Hello, World!");
84
85
// JSON response with custom headers
86
await mockServer.forGet("/api/users")
87
.thenJson(200,
88
{ users: [{ id: 1, name: "Alice" }] },
89
{ "X-Total-Count": "1" }
90
);
91
92
// Binary response with Buffer
93
const imageBuffer = Buffer.from("binary-image-data");
94
await mockServer.forGet("/api/avatar.png")
95
.thenReply(200, imageBuffer, {
96
"Content-Type": "image/png",
97
"Cache-Control": "max-age=3600"
98
});
99
100
// Response with trailers (HTTP/1.1 chunked encoding)
101
await mockServer.forGet("/api/stream")
102
.thenReply(200, "Response body",
103
{ "Transfer-Encoding": "chunked" },
104
{ "X-Checksum": "abc123" }
105
);
106
107
// File response
108
await mockServer.forGet("/download/file.pdf")
109
.thenFromFile(200, "/path/to/file.pdf", {
110
"Content-Type": "application/pdf",
111
"Content-Disposition": "attachment; filename=file.pdf"
112
});
113
```
114
115
### Dynamic Responses
116
117
Generate responses dynamically based on request content using callback functions.
118
119
```typescript { .api }
120
interface RequestRuleBuilder {
121
/**
122
* Generate response dynamically using a callback function.
123
* Callback receives the completed request and returns response configuration.
124
*/
125
thenCallback(
126
callback: (request: CompletedRequest) => CallbackResponseResult | Promise<CallbackResponseResult>
127
): Promise<MockedEndpoint>;
128
}
129
130
interface CallbackResponseResult {
131
statusCode?: number;
132
statusMessage?: string;
133
headers?: Headers;
134
trailers?: Trailers;
135
body?: string | Buffer | Uint8Array | object;
136
json?: object;
137
}
138
139
interface CompletedRequest {
140
id: string;
141
matchedRuleId?: string;
142
protocol: string;
143
httpVersion: string;
144
method: string;
145
url: string;
146
path: string;
147
headers: Headers;
148
body: CompletedBody;
149
timingEvents: TimingEvents;
150
tags: string[];
151
}
152
153
interface CompletedBody {
154
buffer: Buffer;
155
getDecodedBuffer(): Promise<Buffer | undefined>;
156
getText(): Promise<string | undefined>;
157
getJson(): Promise<object | undefined>;
158
getFormData(): Promise<{[key: string]: string | string[] | undefined} | undefined>;
159
}
160
```
161
162
**Usage Examples:**
163
164
```typescript
165
import { getLocal } from "mockttp";
166
167
const mockServer = getLocal();
168
await mockServer.start();
169
170
// Echo request data back
171
await mockServer.forPost("/api/echo")
172
.thenCallback(async (request) => {
173
const body = await request.body.getText();
174
return {
175
statusCode: 200,
176
headers: { "Content-Type": "text/plain" },
177
body: `Echo: ${body}`
178
};
179
});
180
181
// Dynamic JSON response based on request
182
await mockServer.forGet("/api/user/*")
183
.thenCallback(async (request) => {
184
const userId = request.path.split('/').pop();
185
const userAgent = request.headers['user-agent'] || 'unknown';
186
187
return {
188
json: {
189
id: userId,
190
userAgent: userAgent,
191
timestamp: new Date().toISOString()
192
}
193
};
194
});
195
196
// Conditional response based on headers
197
await mockServer.forPost("/api/auth")
198
.thenCallback(async (request) => {
199
const authHeader = request.headers.authorization;
200
201
if (authHeader === 'Bearer valid-token') {
202
return { statusCode: 200, json: { authenticated: true } };
203
} else {
204
return {
205
statusCode: 401,
206
json: { error: "Invalid token" },
207
headers: { "WWW-Authenticate": "Bearer" }
208
};
209
}
210
});
211
212
// Process form data
213
await mockServer.forPost("/api/contact")
214
.thenCallback(async (request) => {
215
const formData = await request.body.getFormData();
216
const email = formData?.email;
217
218
if (email && typeof email === 'string') {
219
return {
220
statusCode: 200,
221
json: { message: `Thank you, ${email}!` }
222
};
223
} else {
224
return {
225
statusCode: 400,
226
json: { error: "Email required" }
227
};
228
}
229
});
230
```
231
232
### Stream Responses
233
234
Send responses from readable streams for large files or real-time data.
235
236
```typescript { .api }
237
interface RequestRuleBuilder {
238
/**
239
* Send response from a readable stream.
240
* Useful for large files or streaming data.
241
*/
242
thenStream(
243
status: number,
244
stream: stream.Readable,
245
headers?: Headers
246
): Promise<MockedEndpoint>;
247
}
248
```
249
250
**Usage Examples:**
251
252
```typescript
253
import { getLocal } from "mockttp";
254
import * as fs from "fs";
255
import { Readable } from "stream";
256
257
const mockServer = getLocal();
258
await mockServer.start();
259
260
// Stream file response
261
await mockServer.forGet("/api/large-file")
262
.thenStream(200,
263
fs.createReadStream("/path/to/large-file.json"),
264
{ "Content-Type": "application/json" }
265
);
266
267
// Stream generated data
268
await mockServer.forGet("/api/live-data")
269
.thenStream(200,
270
Readable.from(generateDataStream()),
271
{
272
"Content-Type": "text/plain",
273
"Transfer-Encoding": "chunked"
274
}
275
);
276
277
async function* generateDataStream() {
278
for (let i = 0; i < 1000; i++) {
279
yield `Data chunk ${i}\n`;
280
await new Promise(resolve => setTimeout(resolve, 10));
281
}
282
}
283
```
284
285
### Request Forwarding
286
287
Forward requests to real servers with optional transformations.
288
289
```typescript { .api }
290
interface RequestRuleBuilder {
291
/**
292
* Forward request to the original target server.
293
* Useful for selective mocking while allowing real traffic through.
294
*/
295
thenPassThrough(options?: PassThroughStepOptions): Promise<MockedEndpoint>;
296
297
/**
298
* Forward request to a specific target URL.
299
* Enables request proxying and redirection.
300
*/
301
thenForwardTo(
302
target: string,
303
options?: PassThroughStepOptions
304
): Promise<MockedEndpoint>;
305
}
306
307
interface PassThroughStepOptions {
308
/**
309
* Transformations to apply to outgoing request.
310
*/
311
transformRequest?: RequestTransform;
312
313
/**
314
* Transformations to apply to incoming response.
315
*/
316
transformResponse?: ResponseTransform;
317
318
/**
319
* Custom DNS lookup function for request destination.
320
*/
321
lookupOptions?: PassThroughLookupOptions;
322
323
/**
324
* Connection options for upstream request.
325
*/
326
connectionOptions?: PassThroughStepConnectionOptions;
327
328
/**
329
* Initial transforms before forwarding.
330
*/
331
initialTransforms?: PassThroughInitialTransforms;
332
333
/**
334
* Forwarding configuration options.
335
*/
336
forwardingOptions?: ForwardingOptions;
337
}
338
339
interface RequestTransform {
340
updateHeaders?: (headers: Headers) => Headers;
341
updateBody?: (body: Buffer) => Buffer | Promise<Buffer>;
342
}
343
344
interface ResponseTransform {
345
updateStatus?: (status: number) => number;
346
updateHeaders?: (headers: Headers) => Headers;
347
updateBody?: (body: Buffer) => Buffer | Promise<Buffer>;
348
}
349
```
350
351
**Usage Examples:**
352
353
```typescript
354
import { getLocal } from "mockttp";
355
356
const mockServer = getLocal();
357
await mockServer.start();
358
359
// Pass through to original server
360
await mockServer.forGet("/api/external")
361
.thenPassThrough();
362
363
// Forward to different server
364
await mockServer.forPost("/api/proxy")
365
.thenForwardTo("https://api.example.com/v1/data");
366
367
// Forward with request transformation
368
await mockServer.forPost("/api/transform")
369
.thenForwardTo("https://api.example.com/webhook", {
370
transformRequest: {
371
updateHeaders: (headers) => ({
372
...headers,
373
'X-Forwarded-By': 'mockttp',
374
'Authorization': 'Bearer secret-token'
375
})
376
}
377
});
378
379
// Forward with response transformation
380
await mockServer.forGet("/api/filtered")
381
.thenPassThrough({
382
transformResponse: {
383
updateStatus: (status) => status === 404 ? 200 : status,
384
updateBody: async (body) => {
385
const data = JSON.parse(body.toString());
386
return Buffer.from(JSON.stringify({
387
...data,
388
filtered: true,
389
timestamp: Date.now()
390
}));
391
}
392
}
393
});
394
```
395
396
### Connection Control
397
398
Control connection behavior for testing network conditions and error scenarios.
399
400
```typescript { .api }
401
interface RequestRuleBuilder {
402
/**
403
* Close the connection immediately without sending a response.
404
* Simulates server crashes or network failures.
405
*/
406
thenCloseConnection(): Promise<MockedEndpoint>;
407
408
/**
409
* Reset the connection with a TCP RST packet.
410
* Simulates aggressive connection termination.
411
*/
412
thenResetConnection(): Promise<MockedEndpoint>;
413
414
/**
415
* Hold the connection open indefinitely without responding.
416
* Simulates server timeouts and hanging connections.
417
*/
418
thenTimeout(): Promise<MockedEndpoint>;
419
}
420
```
421
422
**Usage Examples:**
423
424
```typescript
425
import { getLocal } from "mockttp";
426
427
const mockServer = getLocal();
428
await mockServer.start();
429
430
// Simulate server crash
431
await mockServer.forPost("/api/unreliable")
432
.thenCloseConnection();
433
434
// Simulate connection reset
435
await mockServer.forGet("/api/forbidden")
436
.thenResetConnection();
437
438
// Simulate slow/hanging server
439
await mockServer.forGet("/api/slow")
440
.thenTimeout();
441
442
// Combined with execution control for flaky behavior
443
await mockServer.forPost("/api/flaky")
444
.twice()
445
.thenCloseConnection();
446
447
// Then add a fallback rule
448
await mockServer.forPost("/api/flaky")
449
.thenReply(200, { success: true });
450
```
451
452
### Response Timing
453
454
Add delays to simulate network latency and slow servers.
455
456
```typescript { .api }
457
interface RequestRuleBuilder {
458
/**
459
* Add a delay before processing the next step.
460
* Can be chained with other response actions.
461
*/
462
delay(ms: number): this;
463
}
464
```
465
466
**Usage Examples:**
467
468
```typescript
469
import { getLocal } from "mockttp";
470
471
const mockServer = getLocal();
472
await mockServer.start();
473
474
// Slow response simulation
475
await mockServer.forGet("/api/slow")
476
.delay(2000) // 2 second delay
477
.thenReply(200, { data: "finally!" });
478
479
// Variable delay with callback
480
await mockServer.forGet("/api/variable")
481
.delay(Math.random() * 1000) // 0-1 second random delay
482
.thenJson(200, { timestamp: Date.now() });
483
484
// Delayed forwarding
485
await mockServer.forPost("/api/slow-proxy")
486
.delay(500)
487
.thenForwardTo("https://slow-api.example.com/endpoint");
488
```
489
490
### JSON-RPC Responses
491
492
Specialized responses for JSON-RPC protocol support.
493
494
```typescript { .api }
495
interface RequestRuleBuilder {
496
/**
497
* Send a JSON-RPC success response with the given result.
498
* Automatically formats with jsonrpc: "2.0" and proper structure.
499
*/
500
thenSendJsonRpcResult(
501
result: any,
502
id?: string | number
503
): Promise<MockedEndpoint>;
504
505
/**
506
* Send a JSON-RPC error response with the given error details.
507
* Automatically formats with jsonrpc: "2.0" and proper error structure.
508
*/
509
thenSendJsonRpcError(
510
error: {code: number, message: string, data?: any},
511
id?: string | number
512
): Promise<MockedEndpoint>;
513
}
514
```
515
516
**Usage Examples:**
517
518
```typescript
519
import { getLocal } from "mockttp";
520
521
const mockServer = getLocal();
522
await mockServer.start();
523
524
// JSON-RPC success response
525
await mockServer.forJsonRpcRequest({ method: "getUser" })
526
.thenSendJsonRpcResult({
527
id: 123,
528
name: "Alice",
529
email: "alice@example.com"
530
});
531
532
// JSON-RPC error response
533
await mockServer.forJsonRpcRequest({ method: "deleteUser" })
534
.thenSendJsonRpcError({
535
code: -32602,
536
message: "Invalid params",
537
data: { required: ["id"] }
538
});
539
540
// Dynamic JSON-RPC with callback
541
await mockServer.forJsonRpcRequest()
542
.thenCallback(async (request) => {
543
const body = await request.body.getJson() as any;
544
545
if (body.method === "add") {
546
const [a, b] = body.params;
547
return {
548
json: {
549
jsonrpc: "2.0",
550
result: a + b,
551
id: body.id
552
}
553
};
554
} else {
555
return {
556
json: {
557
jsonrpc: "2.0",
558
error: {
559
code: -32601,
560
message: "Method not found"
561
},
562
id: body.id
563
}
564
};
565
}
566
});
567
```
568
569
### Response Chaining
570
571
Multiple response actions can be chained for complex scenarios:
572
573
```typescript
574
import { getLocal } from "mockttp";
575
576
const mockServer = getLocal();
577
await mockServer.start();
578
579
// Delayed response with custom headers
580
await mockServer.forGet("/api/complex")
581
.delay(1000)
582
.thenReply(200, "Success", {
583
"X-Processing-Time": "1000",
584
"X-Server": "mockttp"
585
});
586
```
587
588
All response methods return `Promise<MockedEndpoint>` which provides access to the created rule for monitoring and testing.