Elegant & feature rich browser / node HTTP with a fluent API
—
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.
Default serialization functions for converting request data to appropriate formats.
/**
* Global serializer configuration object
*/
const serialize = {
'application/json': Function,
'application/x-www-form-urlencoded': Function
};
// Available serializers
serialize['application/json']: (obj: any) => string;
serialize['application/x-www-form-urlencoded']: (obj: object) => string;Usage Examples:
const superagent = require('superagent');
// JSON serialization (automatic)
superagent
.post('https://api.example.com/users')
.send({ name: 'John', age: 30 });
// Automatically uses serialize['application/json']
// Form serialization (automatic)
superagent
.post('https://api.example.com/form')
.type('form')
.send({ username: 'user', password: 'pass' });
// Automatically uses serialize['application/x-www-form-urlencoded']
// Access global serializers
console.log('JSON serializer:', superagent.serialize['application/json']);
console.log('Form serializer:', superagent.serialize['application/x-www-form-urlencoded']);
// Custom global serializer
superagent.serialize['application/xml'] = (obj) => {
// Custom XML serialization logic
return `<data>${JSON.stringify(obj)}</data>`;
};Default parsing functions for converting response data from various formats.
/**
* Global parser configuration object
*/
const parse = {
'application/json': Function,
'application/x-www-form-urlencoded': Function,
'text/plain': Function,
'text/*': Function,
'application/octet-stream': Function,
'image/*': Function
};
// Available parsers
parse['application/json']: (res: Response, callback: Function) => void;
parse['application/x-www-form-urlencoded']: (res: Response, callback: Function) => void;
parse['text/plain']: (res: Response, callback: Function) => void;
parse.text: (res: Response, callback: Function) => void;
parse.image: (res: Response, callback: Function) => void;Usage Examples:
// JSON parsing (automatic)
const jsonResponse = await superagent.get('https://api.example.com/data.json');
console.log('Parsed JSON:', jsonResponse.body);
// Text parsing (automatic)
const textResponse = await superagent.get('https://api.example.com/plain.txt');
console.log('Text content:', textResponse.text);
// Binary/Image parsing (automatic)
const imageResponse = await superagent.get('https://api.example.com/image.jpg');
console.log('Binary buffer:', imageResponse.body instanceof Buffer);
// Access global parsers
console.log('JSON parser:', superagent.parse['application/json']);
console.log('Text parser:', superagent.parse.text);
console.log('Image parser:', superagent.parse.image);
// Custom global parser
superagent.parse['application/xml'] = (res, callback) => {
// Custom XML parsing logic
const xmlData = parseXML(res.text);
callback(null, xmlData);
};Override serialization for individual requests.
/**
* Override request serializer function
* @param {function} fn - Custom serializer function
* @returns {Request} Request instance for chaining
*/
Request.prototype.serialize(fn): Request;Usage Examples:
// Custom JSON serialization with pretty printing
superagent
.post('https://api.example.com/data')
.serialize((obj) => JSON.stringify(obj, null, 2))
.send({ message: 'Hello World' });
// Custom form serialization
superagent
.post('https://api.example.com/form')
.type('form')
.serialize((obj) => {
// Custom form encoding with special handling
return Object.keys(obj)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
.join('&');
})
.send({ special_chars: 'hello+world&test' });
// CSV serialization
superagent
.post('https://api.example.com/csv')
.type('text/csv')
.serialize((data) => {
// Convert array of objects to CSV
const headers = Object.keys(data[0]).join(',');
const rows = data.map(row => Object.values(row).join(','));
return [headers, ...rows].join('\n');
})
.send([
{ name: 'John', age: 30 },
{ name: 'Jane', age: 25 }
]);
// XML serialization
superagent
.post('https://api.example.com/xml')
.type('application/xml')
.serialize((obj) => {
function objectToXml(obj, rootName = 'data') {
let xml = `<${rootName}>`;
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'object') {
xml += objectToXml(value, key);
} else {
xml += `<${key}>${value}</${key}>`;
}
}
xml += `</${rootName}>`;
return xml;
}
return objectToXml(obj);
})
.send({ user: { name: 'John', age: 30 } });Override parsing for individual requests.
/**
* Override response parser function
* @param {function} fn - Custom parser function (res, callback) => void
* @returns {Request} Request instance for chaining
*/
Request.prototype.parse(fn): Request;Usage Examples:
// Custom JSON parser with error handling
superagent
.get('https://api.example.com/data')
.parse((res, callback) => {
try {
const data = JSON.parse(res.text);
callback(null, data);
} catch (err) {
callback(new Error('Invalid JSON: ' + err.message));
}
})
.end((err, res) => {
if (err) {
console.error('Parse error:', err.message);
} else {
console.log('Parsed data:', res.body);
}
});
// CSV parser
superagent
.get('https://api.example.com/data.csv')
.parse((res, callback) => {
const lines = res.text.split('\n');
const headers = lines[0].split(',');
const data = lines.slice(1).map(line => {
const values = line.split(',');
const obj = {};
headers.forEach((header, index) => {
obj[header.trim()] = values[index]?.trim();
});
return obj;
});
callback(null, data);
})
.end((err, res) => {
console.log('CSV data:', res.body);
});
// XML parser
superagent
.get('https://api.example.com/data.xml')
.parse((res, callback) => {
// Simple XML parsing (in practice, use a proper XML parser)
const xmlData = {};
const matches = res.text.match(/<(\w+)>([^<]+)<\/\1>/g);
if (matches) {
matches.forEach(match => {
const [, key, value] = match.match(/<(\w+)>([^<]+)<\/\1>/);
xmlData[key] = value;
});
}
callback(null, xmlData);
});
// Binary data parser with validation
superagent
.get('https://api.example.com/file.pdf')
.parse((res, callback) => {
const buffer = Buffer.from(res.body);
// Validate PDF header
if (buffer.slice(0, 4).toString() !== '%PDF') {
return callback(new Error('Invalid PDF file'));
}
callback(null, {
type: 'pdf',
size: buffer.length,
buffer: buffer
});
});
// Custom text parser with encoding detection
superagent
.get('https://api.example.com/text')
.parse((res, callback) => {
let text = res.text;
// Handle different encodings or formats
if (res.charset === 'iso-8859-1') {
// Convert from Latin-1 to UTF-8
text = Buffer.from(text, 'latin1').toString('utf8');
}
// Additional text processing
const processedText = text
.replace(/\r\n/g, '\n') // Normalize line endings
.trim(); // Remove whitespace
callback(null, processedText);
});Automatic parser selection based on response content type.
// Automatic parser selection examples
// JSON response - uses parse['application/json']
const jsonResponse = await superagent.get('https://api.example.com/users');
// Content-Type: application/json
console.log(typeof jsonResponse.body); // 'object'
// Text response - uses parse.text
const textResponse = await superagent.get('https://api.example.com/readme.txt');
// Content-Type: text/plain
console.log(typeof textResponse.body); // 'string'
// Binary response - uses parse.image
const binaryResponse = await superagent.get('https://api.example.com/file.pdf');
// Content-Type: application/pdf
console.log(binaryResponse.body instanceof Buffer); // true
// Form response - uses parse['application/x-www-form-urlencoded']
const formResponse = await superagent.get('https://api.example.com/form-data');
// Content-Type: application/x-www-form-urlencoded
console.log(typeof formResponse.body); // 'object'Configure response buffering behavior for different content types.
/**
* Global buffer configuration object
*/
const buffer = {};
// Configure buffering for specific content types
buffer['application/json'] = boolean;
buffer['text/plain'] = boolean;
buffer['image/*'] = boolean;Usage Examples:
// Configure global buffering
superagent.buffer['application/json'] = true; // Buffer JSON responses
superagent.buffer['text/plain'] = true; // Buffer text responses
superagent.buffer['image/jpeg'] = false; // Don't buffer images
// Request-level buffering override
superagent
.get('https://api.example.com/large-json')
.buffer(false) // Don't buffer this large response
.parse((res, callback) => {
// Handle streaming response
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(data);
callback(null, parsed);
} catch (err) {
callback(err);
}
});
});Complex parsing scenarios and patterns.
// Multi-format parser based on content
superagent
.get('https://api.example.com/dynamic-format')
.parse((res, callback) => {
const contentType = res.headers['content-type'] || '';
if (contentType.includes('application/json')) {
try {
callback(null, JSON.parse(res.text));
} catch (err) {
callback(err);
}
} else if (contentType.includes('application/xml')) {
// Parse XML
callback(null, parseXML(res.text));
} else if (contentType.includes('text/csv')) {
// Parse CSV
callback(null, parseCSV(res.text));
} else {
// Default to text
callback(null, res.text);
}
});
// Streaming parser for large responses
superagent
.get('https://api.example.com/large-dataset')
.buffer(false)
.parse((res, callback) => {
const results = [];
let buffer = '';
res.on('data', (chunk) => {
buffer += chunk;
// Process complete JSON objects (newline-delimited JSON)
const lines = buffer.split('\n');
buffer = lines.pop(); // Keep incomplete line
lines.forEach(line => {
if (line.trim()) {
try {
results.push(JSON.parse(line));
} catch (err) {
// Skip invalid lines
}
}
});
});
res.on('end', () => {
// Process remaining buffer
if (buffer.trim()) {
try {
results.push(JSON.parse(buffer));
} catch (err) {
// Ignore final parse error
}
}
callback(null, results);
});
res.on('error', callback);
});
// Conditional parser with fallback
superagent
.get('https://api.example.com/data')
.parse((res, callback) => {
// Try JSON first
try {
const jsonData = JSON.parse(res.text);
callback(null, { format: 'json', data: jsonData });
return;
} catch (jsonErr) {
// Fall back to form data
try {
const formData = parseFormData(res.text);
callback(null, { format: 'form', data: formData });
return;
} catch (formErr) {
// Fall back to plain text
callback(null, { format: 'text', data: res.text });
}
}
});Handle parsing errors gracefully.
// Robust JSON parser with error recovery
superagent
.get('https://api.example.com/potentially-invalid-json')
.parse((res, callback) => {
try {
const data = JSON.parse(res.text);
callback(null, data);
} catch (err) {
// Attempt to fix common JSON issues
let fixedText = res.text
.replace(/,\s*}/g, '}') // Remove trailing commas
.replace(/,\s*]/g, ']') // Remove trailing commas in arrays
.replace(/'/g, '"'); // Replace single quotes with double quotes
try {
const fixedData = JSON.parse(fixedText);
console.warn('JSON was malformed but successfully repaired');
callback(null, fixedData);
} catch (secondErr) {
// If repair fails, return original error with more context
const error = new Error(`JSON parsing failed: ${err.message}`);
error.originalText = res.text;
error.responseStatus = res.status;
callback(error);
}
}
});
// Parser with validation
superagent
.get('https://api.example.com/api-data')
.parse((res, callback) => {
try {
const data = JSON.parse(res.text);
// Validate expected structure
if (!data.hasOwnProperty('success')) {
return callback(new Error('Missing required field: success'));
}
if (!Array.isArray(data.items)) {
return callback(new Error('Expected items to be an array'));
}
callback(null, data);
} catch (err) {
callback(err);
}
});Install with Tessl CLI
npx tessl i tessl/npm-superagent