0
# Body Processing
1
2
Unified interface for reading and processing request/response bodies with support for multiple formats including JSON, text, binary data, form data, and streams.
3
4
## Capabilities
5
6
### Body Interface
7
8
Shared interface implemented by both Request and Response classes for consistent body handling.
9
10
```javascript { .api }
11
/**
12
* Body interface for reading request/response content
13
*/
14
interface Body {
15
readonly body: ReadableStream | null;
16
readonly bodyUsed: boolean;
17
readonly size: number;
18
19
arrayBuffer(): Promise<ArrayBuffer>;
20
blob(): Promise<Blob>;
21
formData(): Promise<FormData>;
22
json(): Promise<any>;
23
text(): Promise<string>;
24
25
/** @deprecated Use arrayBuffer() instead */
26
buffer(): Promise<Buffer>;
27
}
28
```
29
30
**Usage Examples:**
31
32
```javascript
33
import fetch from 'node-fetch';
34
35
const response = await fetch('https://api.github.com/users/octocat');
36
37
// Check if body has been consumed
38
console.log(response.bodyUsed); // false
39
40
// Read as JSON
41
const userData = await response.json();
42
console.log(response.bodyUsed); // true
43
44
// Cannot read again after consumption
45
try {
46
await response.text(); // This will throw an error
47
} catch (error) {
48
console.error('Body already used:', error.message);
49
}
50
```
51
52
### JSON Processing
53
54
Parse response bodies as JSON with automatic error handling for malformed JSON.
55
56
```javascript { .api }
57
/**
58
* Parse body as JSON
59
* @returns Promise resolving to parsed JSON data
60
* @throws SyntaxError if JSON is malformed
61
*/
62
json(): Promise<any>;
63
```
64
65
**Usage Examples:**
66
67
```javascript
68
// API response as JSON
69
const response = await fetch('https://api.github.com/users/octocat');
70
const userData = await response.json();
71
72
console.log(userData.login); // 'octocat'
73
console.log(userData.id); // 583231
74
console.log(userData.name); // 'The Octocat'
75
76
// Handle JSON parsing errors
77
try {
78
const response = await fetch('https://example.com/malformed-json');
79
const data = await response.json();
80
} catch (error) {
81
if (error instanceof SyntaxError) {
82
console.error('Invalid JSON response:', error.message);
83
}
84
}
85
86
// POST request with JSON response
87
const postResponse = await fetch('https://httpbin.org/post', {
88
method: 'POST',
89
headers: { 'Content-Type': 'application/json' },
90
body: JSON.stringify({ name: 'Alice', age: 30 })
91
});
92
const result = await postResponse.json();
93
console.log(result.json); // { name: 'Alice', age: 30 }
94
```
95
96
### Text Processing
97
98
Read response bodies as plain text with automatic UTF-8 decoding.
99
100
```javascript { .api }
101
/**
102
* Read body as text string
103
* @returns Promise resolving to text content
104
*/
105
text(): Promise<string>;
106
```
107
108
**Usage Examples:**
109
110
```javascript
111
// HTML content
112
const response = await fetch('https://example.com');
113
const htmlContent = await response.text();
114
console.log(htmlContent); // '<!DOCTYPE html><html>...'
115
116
// Plain text API
117
const textResponse = await fetch('https://httpbin.org/uuid');
118
const uuid = await textResponse.text();
119
console.log(uuid.trim()); // 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
120
121
// CSV data
122
const csvResponse = await fetch('https://example.com/data.csv');
123
const csvContent = await csvResponse.text();
124
const rows = csvContent.split('\n');
125
console.log('Number of rows:', rows.length);
126
127
// Large text processing
128
const largeTextResponse = await fetch('https://example.com/large-file.txt');
129
const text = await largeTextResponse.text();
130
console.log('File size:', text.length, 'characters');
131
```
132
133
### Binary Data Processing
134
135
Handle binary data as ArrayBuffer for images, files, and other binary content.
136
137
```javascript { .api }
138
/**
139
* Read body as ArrayBuffer
140
* @returns Promise resolving to ArrayBuffer
141
*/
142
arrayBuffer(): Promise<ArrayBuffer>;
143
```
144
145
**Usage Examples:**
146
147
```javascript
148
// Download image as binary data
149
const imageResponse = await fetch('https://github.com/images/error/octocat_happy.gif');
150
const imageBuffer = await imageResponse.arrayBuffer();
151
152
// Save to file (Node.js)
153
import { writeFileSync } from 'fs';
154
writeFileSync('octocat.gif', Buffer.from(imageBuffer));
155
156
// Process binary data
157
const uint8Array = new Uint8Array(imageBuffer);
158
console.log('File size:', uint8Array.length, 'bytes');
159
console.log('First 4 bytes:', Array.from(uint8Array.slice(0, 4)).map(b => b.toString(16)));
160
161
// Download ZIP file
162
const zipResponse = await fetch('https://example.com/archive.zip');
163
const zipBuffer = await zipResponse.arrayBuffer();
164
console.log('ZIP file size:', zipBuffer.byteLength, 'bytes');
165
166
// Handle different binary formats
167
const pdfResponse = await fetch('https://example.com/document.pdf');
168
const pdfBuffer = await pdfResponse.arrayBuffer();
169
// Process PDF data...
170
```
171
172
### Buffer Processing (Deprecated)
173
174
**⚠️ DEPRECATED**: The `buffer()` method is deprecated in favor of `arrayBuffer()`. Use `arrayBuffer()` for new code.
175
176
```javascript { .api }
177
/**
178
* Read body as Buffer (Node.js specific)
179
* @deprecated Use response.arrayBuffer() instead
180
* @returns Promise resolving to Buffer
181
*/
182
buffer(): Promise<Buffer>;
183
```
184
185
**Migration Example:**
186
187
```javascript
188
// OLD - Deprecated approach
189
const response = await fetch('https://example.com/file.pdf');
190
const buffer = await response.buffer(); // ⚠️ Deprecated
191
192
// NEW - Recommended approach
193
const response = await fetch('https://example.com/file.pdf');
194
const arrayBuffer = await response.arrayBuffer();
195
const buffer = Buffer.from(arrayBuffer);
196
197
// Or for Node.js compatibility
198
const response = await fetch('https://example.com/file.pdf');
199
const buffer = Buffer.from(await response.arrayBuffer());
200
```
201
202
**Why migrate from buffer() to arrayBuffer()?**
203
204
- **Web Standards Compliance**: `arrayBuffer()` is part of the standard Fetch API
205
- **Cross-platform Compatibility**: Works in both Node.js and browsers
206
- **Future-proof**: The `buffer()` method will be removed in future versions
207
- **Better Type Safety**: `ArrayBuffer` provides clearer type semantics
208
209
### Blob Processing
210
211
Convert response bodies to Blob objects for file-like operations.
212
213
```javascript { .api }
214
/**
215
* Read body as Blob
216
* @returns Promise resolving to Blob object
217
*/
218
blob(): Promise<Blob>;
219
```
220
221
**Usage Examples:**
222
223
```javascript
224
// Create blob from response
225
const imageResponse = await fetch('https://example.com/image.jpg');
226
const imageBlob = await imageResponse.blob();
227
228
console.log('Blob size:', imageBlob.size);
229
console.log('Blob type:', imageBlob.type); // 'image/jpeg'
230
231
// Convert blob to other formats
232
const arrayBuffer = await imageBlob.arrayBuffer();
233
const text = await imageBlob.text();
234
235
// Create object URL (browser environment)
236
if (typeof URL !== 'undefined') {
237
const objectUrl = URL.createObjectURL(imageBlob);
238
console.log('Object URL:', objectUrl);
239
240
// Don't forget to revoke when done
241
URL.revokeObjectURL(objectUrl);
242
}
243
244
// Stream blob data
245
const stream = imageBlob.stream();
246
const reader = stream.getReader();
247
248
while (true) {
249
const { done, value } = await reader.read();
250
if (done) break;
251
console.log('Chunk size:', value.length);
252
}
253
```
254
255
### Form Data Processing
256
257
Parse multipart/form-data and application/x-www-form-urlencoded content.
258
259
```javascript { .api }
260
/**
261
* Parse body as FormData
262
* @returns Promise resolving to FormData object
263
* @throws Error if content is not form data
264
*/
265
formData(): Promise<FormData>;
266
```
267
268
**Usage Examples:**
269
270
```javascript
271
// Parse multipart form data
272
const formResponse = await fetch('https://httpbin.org/post', {
273
method: 'POST',
274
body: new FormData() // This would be received as form data
275
});
276
277
const formData = await formResponse.formData();
278
279
// Iterate over form fields
280
for (const [name, value] of formData.entries()) {
281
console.log(`${name}: ${value}`);
282
}
283
284
// Get specific field
285
const username = formData.get('username');
286
const avatar = formData.get('avatar'); // Could be a File object
287
288
// Parse URL-encoded form data
289
const urlEncodedResponse = await fetch('https://httpbin.org/post', {
290
method: 'POST',
291
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
292
body: 'name=Alice&email=alice@example.com'
293
});
294
295
const parsedForm = await urlEncodedResponse.formData();
296
console.log(parsedForm.get('name')); // 'Alice'
297
console.log(parsedForm.get('email')); // 'alice@example.com'
298
```
299
300
### Stream Processing
301
302
Access the underlying ReadableStream for streaming data processing.
303
304
```javascript { .api }
305
/**
306
* Access to the underlying ReadableStream
307
*/
308
interface StreamAccess {
309
readonly body: ReadableStream | null;
310
}
311
```
312
313
**Usage Examples:**
314
315
```javascript
316
import { pipeline } from 'stream/promises';
317
import { createWriteStream } from 'fs';
318
319
// Stream large file download
320
const response = await fetch('https://example.com/large-file.zip');
321
322
if (!response.ok) {
323
throw new Error(`HTTP error! status: ${response.status}`);
324
}
325
326
// Pipe response stream to file
327
await pipeline(response.body, createWriteStream('./large-file.zip'));
328
console.log('Download completed');
329
330
// Process streaming JSON data
331
const streamResponse = await fetch('https://httpbin.org/stream/10');
332
333
// Read stream chunk by chunk
334
const reader = streamResponse.body.getReader();
335
const decoder = new TextDecoder();
336
337
while (true) {
338
const { done, value } = await reader.read();
339
340
if (done) break;
341
342
const chunk = decoder.decode(value, { stream: true });
343
console.log('Received chunk:', chunk);
344
}
345
346
// Stream with async iteration (Node.js 10+)
347
const asyncStreamResponse = await fetch('https://httpbin.org/stream/5');
348
349
try {
350
for await (const chunk of asyncStreamResponse.body) {
351
const text = chunk.toString();
352
console.log('Processed chunk:', text);
353
}
354
} catch (error) {
355
console.error('Stream error:', error);
356
}
357
```
358
359
### Body Size and Limits
360
361
Control and monitor body size limits for security and performance.
362
363
```javascript { .api }
364
interface BodyLimits {
365
readonly size: number; // Size limit in bytes (0 = unlimited)
366
}
367
```
368
369
**Usage Examples:**
370
371
```javascript
372
// Set response size limit
373
const response = await fetch('https://example.com/large-file', {
374
size: 1024 * 1024 // Limit to 1MB
375
});
376
377
try {
378
const data = await response.arrayBuffer();
379
console.log('Downloaded:', data.byteLength, 'bytes');
380
} catch (error) {
381
if (error.type === 'max-size') {
382
console.error('Response too large:', error.message);
383
}
384
}
385
386
// Check body size before processing
387
if (response.headers.has('content-length')) {
388
const contentLength = parseInt(response.headers.get('content-length'));
389
if (contentLength > 10 * 1024 * 1024) { // 10MB
390
console.warn('Large response detected:', contentLength, 'bytes');
391
}
392
}
393
```
394
395
### Body Usage Patterns
396
397
Common patterns for handling different types of response bodies.
398
399
```javascript { .api }
400
interface BodyUsagePattern {
401
// Pattern for API responses
402
handleApiResponse<T>(): Promise<T>;
403
404
// Pattern for file downloads
405
handleFileDownload(): Promise<Buffer>;
406
407
// Pattern for streaming data
408
handleStreamingData(): AsyncIterableIterator<Uint8Array>;
409
}
410
```
411
412
**Usage Examples:**
413
414
```javascript
415
// API response handler with error checking
416
async function handleApiResponse(url, options = {}) {
417
const response = await fetch(url, options);
418
419
if (!response.ok) {
420
const errorText = await response.text();
421
throw new Error(`API Error ${response.status}: ${errorText}`);
422
}
423
424
const contentType = response.headers.get('content-type');
425
426
if (contentType?.includes('application/json')) {
427
return await response.json();
428
} else if (contentType?.includes('text/')) {
429
return await response.text();
430
} else {
431
return await response.arrayBuffer();
432
}
433
}
434
435
// File download with progress tracking
436
async function downloadFile(url, onProgress) {
437
const response = await fetch(url);
438
const contentLength = response.headers.get('content-length');
439
const total = contentLength ? parseInt(contentLength) : 0;
440
441
let loaded = 0;
442
const chunks = [];
443
444
const reader = response.body.getReader();
445
446
while (true) {
447
const { done, value } = await reader.read();
448
449
if (done) break;
450
451
chunks.push(value);
452
loaded += value.length;
453
454
if (onProgress && total > 0) {
455
onProgress({ loaded, total, percentage: (loaded / total) * 100 });
456
}
457
}
458
459
return Buffer.concat(chunks);
460
}
461
462
// Usage
463
const fileData = await downloadFile('https://example.com/file.zip', (progress) => {
464
console.log(`Download progress: ${progress.percentage.toFixed(1)}%`);
465
});
466
```