0
# Parsers & Serializers
1
2
Configurable content-type parsing and serialization for different data formats, with built-in support for JSON, form data, text, and binary content, plus extensible custom parser system.
3
4
## Capabilities
5
6
### Global Serializers
7
8
Default serialization functions for converting request data to appropriate formats.
9
10
```javascript { .api }
11
/**
12
* Global serializer configuration object
13
*/
14
const serialize = {
15
'application/json': Function,
16
'application/x-www-form-urlencoded': Function
17
};
18
19
// Available serializers
20
serialize['application/json']: (obj: any) => string;
21
serialize['application/x-www-form-urlencoded']: (obj: object) => string;
22
```
23
24
**Usage Examples:**
25
26
```javascript
27
const superagent = require('superagent');
28
29
// JSON serialization (automatic)
30
superagent
31
.post('https://api.example.com/users')
32
.send({ name: 'John', age: 30 });
33
// Automatically uses serialize['application/json']
34
35
// Form serialization (automatic)
36
superagent
37
.post('https://api.example.com/form')
38
.type('form')
39
.send({ username: 'user', password: 'pass' });
40
// Automatically uses serialize['application/x-www-form-urlencoded']
41
42
// Access global serializers
43
console.log('JSON serializer:', superagent.serialize['application/json']);
44
console.log('Form serializer:', superagent.serialize['application/x-www-form-urlencoded']);
45
46
// Custom global serializer
47
superagent.serialize['application/xml'] = (obj) => {
48
// Custom XML serialization logic
49
return `<data>${JSON.stringify(obj)}</data>`;
50
};
51
```
52
53
### Global Parsers
54
55
Default parsing functions for converting response data from various formats.
56
57
```javascript { .api }
58
/**
59
* Global parser configuration object
60
*/
61
const parse = {
62
'application/json': Function,
63
'application/x-www-form-urlencoded': Function,
64
'text/plain': Function,
65
'text/*': Function,
66
'application/octet-stream': Function,
67
'image/*': Function
68
};
69
70
// Available parsers
71
parse['application/json']: (res: Response, callback: Function) => void;
72
parse['application/x-www-form-urlencoded']: (res: Response, callback: Function) => void;
73
parse['text/plain']: (res: Response, callback: Function) => void;
74
parse.text: (res: Response, callback: Function) => void;
75
parse.image: (res: Response, callback: Function) => void;
76
```
77
78
**Usage Examples:**
79
80
```javascript
81
// JSON parsing (automatic)
82
const jsonResponse = await superagent.get('https://api.example.com/data.json');
83
console.log('Parsed JSON:', jsonResponse.body);
84
85
// Text parsing (automatic)
86
const textResponse = await superagent.get('https://api.example.com/plain.txt');
87
console.log('Text content:', textResponse.text);
88
89
// Binary/Image parsing (automatic)
90
const imageResponse = await superagent.get('https://api.example.com/image.jpg');
91
console.log('Binary buffer:', imageResponse.body instanceof Buffer);
92
93
// Access global parsers
94
console.log('JSON parser:', superagent.parse['application/json']);
95
console.log('Text parser:', superagent.parse.text);
96
console.log('Image parser:', superagent.parse.image);
97
98
// Custom global parser
99
superagent.parse['application/xml'] = (res, callback) => {
100
// Custom XML parsing logic
101
const xmlData = parseXML(res.text);
102
callback(null, xmlData);
103
};
104
```
105
106
### Request-Level Serialization
107
108
Override serialization for individual requests.
109
110
```javascript { .api }
111
/**
112
* Override request serializer function
113
* @param {function} fn - Custom serializer function
114
* @returns {Request} Request instance for chaining
115
*/
116
Request.prototype.serialize(fn): Request;
117
```
118
119
**Usage Examples:**
120
121
```javascript
122
// Custom JSON serialization with pretty printing
123
superagent
124
.post('https://api.example.com/data')
125
.serialize((obj) => JSON.stringify(obj, null, 2))
126
.send({ message: 'Hello World' });
127
128
// Custom form serialization
129
superagent
130
.post('https://api.example.com/form')
131
.type('form')
132
.serialize((obj) => {
133
// Custom form encoding with special handling
134
return Object.keys(obj)
135
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
136
.join('&');
137
})
138
.send({ special_chars: 'hello+world&test' });
139
140
// CSV serialization
141
superagent
142
.post('https://api.example.com/csv')
143
.type('text/csv')
144
.serialize((data) => {
145
// Convert array of objects to CSV
146
const headers = Object.keys(data[0]).join(',');
147
const rows = data.map(row => Object.values(row).join(','));
148
return [headers, ...rows].join('\n');
149
})
150
.send([
151
{ name: 'John', age: 30 },
152
{ name: 'Jane', age: 25 }
153
]);
154
155
// XML serialization
156
superagent
157
.post('https://api.example.com/xml')
158
.type('application/xml')
159
.serialize((obj) => {
160
function objectToXml(obj, rootName = 'data') {
161
let xml = `<${rootName}>`;
162
for (const [key, value] of Object.entries(obj)) {
163
if (typeof value === 'object') {
164
xml += objectToXml(value, key);
165
} else {
166
xml += `<${key}>${value}</${key}>`;
167
}
168
}
169
xml += `</${rootName}>`;
170
return xml;
171
}
172
return objectToXml(obj);
173
})
174
.send({ user: { name: 'John', age: 30 } });
175
```
176
177
### Request-Level Parsing
178
179
Override parsing for individual requests.
180
181
```javascript { .api }
182
/**
183
* Override response parser function
184
* @param {function} fn - Custom parser function (res, callback) => void
185
* @returns {Request} Request instance for chaining
186
*/
187
Request.prototype.parse(fn): Request;
188
```
189
190
**Usage Examples:**
191
192
```javascript
193
// Custom JSON parser with error handling
194
superagent
195
.get('https://api.example.com/data')
196
.parse((res, callback) => {
197
try {
198
const data = JSON.parse(res.text);
199
callback(null, data);
200
} catch (err) {
201
callback(new Error('Invalid JSON: ' + err.message));
202
}
203
})
204
.end((err, res) => {
205
if (err) {
206
console.error('Parse error:', err.message);
207
} else {
208
console.log('Parsed data:', res.body);
209
}
210
});
211
212
// CSV parser
213
superagent
214
.get('https://api.example.com/data.csv')
215
.parse((res, callback) => {
216
const lines = res.text.split('\n');
217
const headers = lines[0].split(',');
218
const data = lines.slice(1).map(line => {
219
const values = line.split(',');
220
const obj = {};
221
headers.forEach((header, index) => {
222
obj[header.trim()] = values[index]?.trim();
223
});
224
return obj;
225
});
226
callback(null, data);
227
})
228
.end((err, res) => {
229
console.log('CSV data:', res.body);
230
});
231
232
// XML parser
233
superagent
234
.get('https://api.example.com/data.xml')
235
.parse((res, callback) => {
236
// Simple XML parsing (in practice, use a proper XML parser)
237
const xmlData = {};
238
const matches = res.text.match(/<(\w+)>([^<]+)<\/\1>/g);
239
if (matches) {
240
matches.forEach(match => {
241
const [, key, value] = match.match(/<(\w+)>([^<]+)<\/\1>/);
242
xmlData[key] = value;
243
});
244
}
245
callback(null, xmlData);
246
});
247
248
// Binary data parser with validation
249
superagent
250
.get('https://api.example.com/file.pdf')
251
.parse((res, callback) => {
252
const buffer = Buffer.from(res.body);
253
254
// Validate PDF header
255
if (buffer.slice(0, 4).toString() !== '%PDF') {
256
return callback(new Error('Invalid PDF file'));
257
}
258
259
callback(null, {
260
type: 'pdf',
261
size: buffer.length,
262
buffer: buffer
263
});
264
});
265
266
// Custom text parser with encoding detection
267
superagent
268
.get('https://api.example.com/text')
269
.parse((res, callback) => {
270
let text = res.text;
271
272
// Handle different encodings or formats
273
if (res.charset === 'iso-8859-1') {
274
// Convert from Latin-1 to UTF-8
275
text = Buffer.from(text, 'latin1').toString('utf8');
276
}
277
278
// Additional text processing
279
const processedText = text
280
.replace(/\r\n/g, '\n') // Normalize line endings
281
.trim(); // Remove whitespace
282
283
callback(null, processedText);
284
});
285
```
286
287
### Content-Type Detection
288
289
Automatic parser selection based on response content type.
290
291
```javascript
292
// Automatic parser selection examples
293
294
// JSON response - uses parse['application/json']
295
const jsonResponse = await superagent.get('https://api.example.com/users');
296
// Content-Type: application/json
297
console.log(typeof jsonResponse.body); // 'object'
298
299
// Text response - uses parse.text
300
const textResponse = await superagent.get('https://api.example.com/readme.txt');
301
// Content-Type: text/plain
302
console.log(typeof textResponse.body); // 'string'
303
304
// Binary response - uses parse.image
305
const binaryResponse = await superagent.get('https://api.example.com/file.pdf');
306
// Content-Type: application/pdf
307
console.log(binaryResponse.body instanceof Buffer); // true
308
309
// Form response - uses parse['application/x-www-form-urlencoded']
310
const formResponse = await superagent.get('https://api.example.com/form-data');
311
// Content-Type: application/x-www-form-urlencoded
312
console.log(typeof formResponse.body); // 'object'
313
```
314
315
### Buffering Configuration
316
317
Configure response buffering behavior for different content types.
318
319
```javascript { .api }
320
/**
321
* Global buffer configuration object
322
*/
323
const buffer = {};
324
325
// Configure buffering for specific content types
326
buffer['application/json'] = boolean;
327
buffer['text/plain'] = boolean;
328
buffer['image/*'] = boolean;
329
```
330
331
**Usage Examples:**
332
333
```javascript
334
// Configure global buffering
335
superagent.buffer['application/json'] = true; // Buffer JSON responses
336
superagent.buffer['text/plain'] = true; // Buffer text responses
337
superagent.buffer['image/jpeg'] = false; // Don't buffer images
338
339
// Request-level buffering override
340
superagent
341
.get('https://api.example.com/large-json')
342
.buffer(false) // Don't buffer this large response
343
.parse((res, callback) => {
344
// Handle streaming response
345
let data = '';
346
res.on('data', chunk => data += chunk);
347
res.on('end', () => {
348
try {
349
const parsed = JSON.parse(data);
350
callback(null, parsed);
351
} catch (err) {
352
callback(err);
353
}
354
});
355
});
356
```
357
358
### Advanced Parser Patterns
359
360
Complex parsing scenarios and patterns.
361
362
```javascript
363
// Multi-format parser based on content
364
superagent
365
.get('https://api.example.com/dynamic-format')
366
.parse((res, callback) => {
367
const contentType = res.headers['content-type'] || '';
368
369
if (contentType.includes('application/json')) {
370
try {
371
callback(null, JSON.parse(res.text));
372
} catch (err) {
373
callback(err);
374
}
375
} else if (contentType.includes('application/xml')) {
376
// Parse XML
377
callback(null, parseXML(res.text));
378
} else if (contentType.includes('text/csv')) {
379
// Parse CSV
380
callback(null, parseCSV(res.text));
381
} else {
382
// Default to text
383
callback(null, res.text);
384
}
385
});
386
387
// Streaming parser for large responses
388
superagent
389
.get('https://api.example.com/large-dataset')
390
.buffer(false)
391
.parse((res, callback) => {
392
const results = [];
393
let buffer = '';
394
395
res.on('data', (chunk) => {
396
buffer += chunk;
397
398
// Process complete JSON objects (newline-delimited JSON)
399
const lines = buffer.split('\n');
400
buffer = lines.pop(); // Keep incomplete line
401
402
lines.forEach(line => {
403
if (line.trim()) {
404
try {
405
results.push(JSON.parse(line));
406
} catch (err) {
407
// Skip invalid lines
408
}
409
}
410
});
411
});
412
413
res.on('end', () => {
414
// Process remaining buffer
415
if (buffer.trim()) {
416
try {
417
results.push(JSON.parse(buffer));
418
} catch (err) {
419
// Ignore final parse error
420
}
421
}
422
callback(null, results);
423
});
424
425
res.on('error', callback);
426
});
427
428
// Conditional parser with fallback
429
superagent
430
.get('https://api.example.com/data')
431
.parse((res, callback) => {
432
// Try JSON first
433
try {
434
const jsonData = JSON.parse(res.text);
435
callback(null, { format: 'json', data: jsonData });
436
return;
437
} catch (jsonErr) {
438
// Fall back to form data
439
try {
440
const formData = parseFormData(res.text);
441
callback(null, { format: 'form', data: formData });
442
return;
443
} catch (formErr) {
444
// Fall back to plain text
445
callback(null, { format: 'text', data: res.text });
446
}
447
}
448
});
449
```
450
451
### Error Handling in Parsers
452
453
Handle parsing errors gracefully.
454
455
```javascript
456
// Robust JSON parser with error recovery
457
superagent
458
.get('https://api.example.com/potentially-invalid-json')
459
.parse((res, callback) => {
460
try {
461
const data = JSON.parse(res.text);
462
callback(null, data);
463
} catch (err) {
464
// Attempt to fix common JSON issues
465
let fixedText = res.text
466
.replace(/,\s*}/g, '}') // Remove trailing commas
467
.replace(/,\s*]/g, ']') // Remove trailing commas in arrays
468
.replace(/'/g, '"'); // Replace single quotes with double quotes
469
470
try {
471
const fixedData = JSON.parse(fixedText);
472
console.warn('JSON was malformed but successfully repaired');
473
callback(null, fixedData);
474
} catch (secondErr) {
475
// If repair fails, return original error with more context
476
const error = new Error(`JSON parsing failed: ${err.message}`);
477
error.originalText = res.text;
478
error.responseStatus = res.status;
479
callback(error);
480
}
481
}
482
});
483
484
// Parser with validation
485
superagent
486
.get('https://api.example.com/api-data')
487
.parse((res, callback) => {
488
try {
489
const data = JSON.parse(res.text);
490
491
// Validate expected structure
492
if (!data.hasOwnProperty('success')) {
493
return callback(new Error('Missing required field: success'));
494
}
495
496
if (!Array.isArray(data.items)) {
497
return callback(new Error('Expected items to be an array'));
498
}
499
500
callback(null, data);
501
} catch (err) {
502
callback(err);
503
}
504
});
505
```