0
# Response Definition
1
2
This document covers how to define mock responses for intercepted HTTP requests using nock's Interceptor interface.
3
4
## Basic Response Definition
5
6
The primary method for defining responses is the `reply` method, which has several overloads for different use cases.
7
8
```javascript { .api }
9
interface Interceptor {
10
reply(responseCode?: number, body?: ReplyBody, headers?: ReplyHeaders): Scope;
11
reply(
12
replyFn: (uri: string, body: Body) => ReplyFnResult | Promise<ReplyFnResult>
13
): Scope;
14
reply(
15
replyFnWithCallback: (
16
uri: string,
17
body: Body,
18
callback: (err: NodeJS.ErrnoException | null, result: ReplyFnResult) => void
19
) => void
20
): Scope;
21
reply(
22
statusCode: number,
23
replyBodyFn: (uri: string, body: Body) => ReplyBody | Promise<ReplyBody>,
24
headers?: ReplyHeaders
25
): Scope;
26
reply(
27
statusCode: number,
28
replyBodyFnWithCallback: (
29
uri: string,
30
body: Body,
31
callback: (err: NodeJS.ErrnoException | null, result: ReplyBody) => void
32
) => void,
33
headers?: ReplyHeaders
34
): Scope;
35
}
36
```
37
38
### Static Responses
39
40
```javascript
41
// Basic 200 OK response
42
nock("https://api.example.com")
43
.get("/users")
44
.reply(200);
45
46
// With response body
47
nock("https://api.example.com")
48
.get("/users")
49
.reply(200, [{ id: 1, name: "Alice" }]);
50
51
// With custom headers
52
nock("https://api.example.com")
53
.get("/users")
54
.reply(200, [{ id: 1, name: "Alice" }], {
55
"Content-Type": "application/json",
56
"X-Total-Count": "1"
57
});
58
59
// Different status codes
60
nock("https://api.example.com")
61
.post("/users")
62
.reply(201, { id: 2, name: "Bob" });
63
64
nock("https://api.example.com")
65
.get("/users/999")
66
.reply(404, { error: "User not found" });
67
```
68
69
### Dynamic Responses
70
71
Use functions to generate responses based on the request:
72
73
```javascript
74
// Function returning response data
75
nock("https://api.example.com")
76
.get(/\/users\/(\d+)/)
77
.reply(200, (uri, requestBody) => {
78
const id = uri.match(/\/users\/(\d+)/)[1];
79
return { id: parseInt(id), name: `User ${id}` };
80
});
81
82
// Function returning full response
83
nock("https://api.example.com")
84
.post("/users")
85
.reply((uri, requestBody) => {
86
const user = JSON.parse(requestBody);
87
if (!user.name) {
88
return [400, { error: "Name is required" }];
89
}
90
return [201, { ...user, id: Math.floor(Math.random() * 1000) }];
91
});
92
93
// Async function support
94
nock("https://api.example.com")
95
.get("/users")
96
.reply(async (uri, requestBody) => {
97
// Simulate async operation
98
await new Promise(resolve => setTimeout(resolve, 100));
99
return [200, { message: "Users loaded asynchronously" }];
100
});
101
```
102
103
### Callback-Style Dynamic Responses
104
105
For more complex scenarios requiring callback-style responses:
106
107
```javascript
108
nock("https://api.example.com")
109
.get("/users")
110
.reply(function(uri, requestBody, callback) {
111
// 'this' refers to the interceptor context
112
const req = this.req;
113
114
// Simulate async operation
115
setTimeout(() => {
116
callback(null, [200, { users: [], requestId: req.headers["x-request-id"] }]);
117
}, 100);
118
});
119
```
120
121
## Response Body Types
122
123
```javascript { .api }
124
type ReplyBody = string | Record<string, any> | Buffer | ReadStream;
125
```
126
127
Nock supports various response body types:
128
129
### JSON Objects
130
131
```javascript
132
nock("https://api.example.com")
133
.get("/user")
134
.reply(200, { id: 1, name: "Alice", active: true });
135
```
136
137
### Plain Text
138
139
```javascript
140
nock("https://api.example.com")
141
.get("/status")
142
.reply(200, "Server is healthy");
143
```
144
145
### Buffer Data
146
147
```javascript
148
const imageBuffer = Buffer.from("fake-image-data");
149
nock("https://api.example.com")
150
.get("/image.png")
151
.reply(200, imageBuffer, { "Content-Type": "image/png" });
152
```
153
154
### Stream Data
155
156
```javascript
157
const fs = require("fs");
158
const stream = fs.createReadStream("./test-data.json");
159
160
nock("https://api.example.com")
161
.get("/large-dataset")
162
.reply(200, stream, { "Content-Type": "application/json" });
163
```
164
165
## Error Responses
166
167
### Reply with Error
168
169
Generate network-level errors instead of HTTP error responses:
170
171
```javascript { .api }
172
replyWithError(errorMessage: string | object): Scope;
173
```
174
175
```javascript
176
// String error message
177
nock("https://api.example.com")
178
.get("/users")
179
.replyWithError("Network timeout");
180
181
// Error object
182
nock("https://api.example.com")
183
.get("/users")
184
.replyWithError({
185
code: "ECONNREFUSED",
186
message: "Connection refused"
187
});
188
189
// This will cause the HTTP request to fail with the specified error
190
```
191
192
### Reply with File
193
194
Respond with the contents of a file:
195
196
```javascript { .api }
197
replyWithFile(statusCode: number, fileName: string, headers?: ReplyHeaders): Scope;
198
```
199
200
```javascript
201
nock("https://api.example.com")
202
.get("/config")
203
.replyWithFile(200, "./test-fixtures/config.json", {
204
"Content-Type": "application/json"
205
});
206
```
207
208
## Response Headers
209
210
```javascript { .api }
211
type ReplyHeaders =
212
| Record<string, ReplyHeaderValue>
213
| Map<string, ReplyHeaderValue>
214
| ReplyHeaderValue[];
215
216
type ReplyHeaderValue = string | string[] | ReplyHeaderFunction;
217
218
type ReplyHeaderFunction = (
219
req: ClientRequest,
220
res: IncomingMessage,
221
body: string | Buffer
222
) => string | string[];
223
```
224
225
### Static Headers
226
227
```javascript
228
// Object format
229
nock("https://api.example.com")
230
.get("/users")
231
.reply(200, [], {
232
"Content-Type": "application/json",
233
"X-Total-Count": "0"
234
});
235
236
// Array format (key-value pairs)
237
nock("https://api.example.com")
238
.get("/users")
239
.reply(200, [], [
240
"Content-Type", "application/json",
241
"X-Total-Count", "0"
242
]);
243
244
// Map format
245
const headers = new Map();
246
headers.set("Content-Type", "application/json");
247
headers.set("X-Total-Count", "0");
248
249
nock("https://api.example.com")
250
.get("/users")
251
.reply(200, [], headers);
252
```
253
254
### Multiple Values
255
256
```javascript
257
// Multiple values for same header
258
nock("https://api.example.com")
259
.get("/users")
260
.reply(200, [], {
261
"Set-Cookie": ["session=abc123", "theme=dark"]
262
});
263
```
264
265
### Dynamic Headers
266
267
```javascript
268
nock("https://api.example.com")
269
.get("/users")
270
.reply(200, [], {
271
"Content-Type": "application/json",
272
"X-Request-Time": (req, res, body) => new Date().toISOString(),
273
"X-Body-Length": (req, res, body) => body.length.toString()
274
});
275
```
276
277
## Response Timing
278
279
Control the timing of responses to simulate network latency or slow servers.
280
281
### Basic Delay
282
283
```javascript { .api }
284
delay(ms: number): this;
285
```
286
287
```javascript
288
// Delay response by 1 second
289
nock("https://api.example.com")
290
.get("/users")
291
.delay(1000)
292
.reply(200, []);
293
```
294
295
### Advanced Delay Options
296
297
```javascript { .api }
298
delay(opts: { head?: number; body?: number }): this;
299
```
300
301
```javascript
302
// Separate delays for headers and body
303
nock("https://api.example.com")
304
.get("/users")
305
.delay({
306
head: 100, // Delay headers by 100ms
307
body: 500 // Delay body by additional 500ms
308
})
309
.reply(200, []);
310
```
311
312
### Deprecated Delay Methods
313
314
These methods are deprecated but still supported:
315
316
```javascript { .api }
317
delayBody(timeMs: number): this;
318
delayConnection(timeMs: number): this;
319
```
320
321
```javascript
322
// Deprecated - use delay() instead
323
nock("https://api.example.com")
324
.get("/users")
325
.delayConnection(200)
326
.delayBody(300)
327
.reply(200, []);
328
```
329
330
## Repetition Control
331
332
Control how many times an interceptor can be matched.
333
334
```javascript { .api }
335
interface Interceptor {
336
times(newCounter: number): this;
337
once(): this;
338
twice(): this;
339
thrice(): this;
340
optionally(flag?: boolean): this;
341
}
342
```
343
344
### Specific Repetition Counts
345
346
```javascript
347
// Match exactly 3 times
348
nock("https://api.example.com")
349
.get("/users")
350
.times(3)
351
.reply(200, []);
352
353
// Convenience methods
354
nock("https://api.example.com")
355
.get("/status")
356
.once() // Same as .times(1)
357
.reply(200, "OK");
358
359
nock("https://api.example.com")
360
.get("/health")
361
.twice() // Same as .times(2)
362
.reply(200, "Healthy");
363
364
nock("https://api.example.com")
365
.get("/ping")
366
.thrice() // Same as .times(3)
367
.reply(200, "Pong");
368
```
369
370
### Optional Interceptors
371
372
```javascript
373
// This interceptor is optional for scope.done() checks
374
nock("https://api.example.com")
375
.get("/optional-endpoint")
376
.optionally()
377
.reply(200, "Optional response");
378
379
// Can also be toggled
380
nock("https://api.example.com")
381
.get("/conditional")
382
.optionally(process.env.NODE_ENV === "test")
383
.reply(200, "Conditional response");
384
```
385
386
## Response Function Context
387
388
When using function-based replies, the function receives a context with additional information:
389
390
```javascript { .api }
391
interface ReplyFnContext extends Interceptor {
392
req: ClientRequest & {
393
headers: Record<string, string>;
394
};
395
}
396
```
397
398
```javascript
399
nock("https://api.example.com")
400
.post("/users")
401
.reply(function(uri, requestBody) {
402
// 'this' provides access to the request context
403
const contentType = this.req.headers["content-type"];
404
const userAgent = this.req.headers["user-agent"];
405
406
return [200, {
407
message: "User created",
408
metadata: {
409
contentType,
410
userAgent,
411
timestamp: Date.now()
412
}
413
}];
414
});
415
```