Agent
Promise-based HTTP client for Swift. Supports reactive programming patterns through integration with Combine framework. Simple configuration based on URLRequest objects, functional programming approach, and Swift Concurrency support.
Library
SuperAgent
Overview
SuperAgent is an "elegant HTTP API library" developed as an HTTP client library that works in both Node.js and browsers. With the concept of "small progressive client-side HTTP request library," it enables HTTP communication implementation with the same API on both server-side and client-side. Featuring lightweight design (approximately 50KB minified+gzipped) and expressive chainable API, it has established its position as an optimal HTTP client for modern web development through plugin ecosystem extensibility and flexible asynchronous processing patterns.
Details
SuperAgent 2025 edition continues to evolve as the definitive lightweight HTTP client that achieves cross-platform compatibility between Node.js and browsers. Developed by TJ Holowaychuk and currently maintained by the lads.js team, it boasts over 10 years of development experience. With high affinity to Express.js, it enables HTTP communication implementation on both server-side (using Node.js core http module) and client-side (using XHR) with the same API. Supporting all asynchronous patterns including callbacks, Promises, and async/await, it offers easy feature extension through a rich plugin ecosystem.
Key Features
- Cross-Platform Support: Same API usage in Node.js and browsers
- Lightweight Design: Approximately 50KB lightweight implementation (minified + gzipped)
- Expressive API: Intuitive HTTP request description through method chaining
- Multiple Async Patterns: Support for callback, Promise, and async/await
- Rich Plugin System: Easy feature extension and customization
- Automatic Content Type Handling: Automatic formatting for JSON and form-data
Pros and Cons
Pros
- Same API usage in Node.js and browsers reduces learning costs and code duplication
- Provides rich features while being lightweight, balancing performance and functionality
- Excellent integration with Express.js ecosystem and community support
- Intuitive and readable code writing through method chaining
- Flexible feature extension and customization through plugin system
- Support for all asynchronous patterns: callback, Promise, and async/await
Cons
- Limited complex authentication and middleware features as a single-function HTTP client
- Many features depend on plugins, requiring proper plugin selection
- In large applications, axios or fetch are more standardized
- TypeScript type definitions depend on external libraries, posing type safety challenges
- Limited HTTP/2 support with constraints on latest protocol compatibility
- Requires WeakRef and BigInt polyfills for browser support (Opera 85, iOS Safari 12.2-12.5)
Reference Pages
Code Examples
Installation and Basic Setup
# Install SuperAgent
npm install superagent
# Add TypeScript type definitions (when using TypeScript)
npm install @types/superagent --save-dev
# Using yarn
yarn add superagent
yarn add @types/superagent --dev
# Verification in Node.js environment
node -e "const request = require('superagent'); console.log('SuperAgent installed');"
Basic Requests (GET/POST/PUT/DELETE)
const request = require('superagent');
// Basic GET request
request
.get('https://api.example.com/users')
.end((err, res) => {
if (err) {
console.error('Error:', err);
return;
}
console.log('Status:', res.status);
console.log('Headers:', res.headers);
console.log('Data:', res.body); // Automatically parsed JSON
});
// GET request with query parameters
request
.get('https://api.example.com/users')
.query({ page: 1, limit: 10, sort: 'created_at' })
.set('Accept', 'application/json')
.set('User-Agent', 'MyApp/1.0')
.end((err, res) => {
if (err) throw err;
console.log(`Fetched URL: ${res.request.url}`);
console.log(`User count: ${res.body.length}`);
});
// POST request (sending JSON)
const userData = {
name: 'John Doe',
email: '[email protected]',
age: 30
};
request
.post('https://api.example.com/users')
.send(userData) // Automatically sent as JSON format
.set('Accept', 'application/json')
.set('Authorization', 'Bearer your-jwt-token')
.end((err, res) => {
if (err) {
console.error('User creation error:', err.message);
if (res) {
console.error('Status:', res.status);
console.error('Error details:', res.body);
}
return;
}
if (res.status === 201) {
console.log('User creation successful:', res.body);
console.log(`New user ID: ${res.body.id}`);
}
});
// POST request (sending form data)
request
.post('https://api.example.com/login')
.type('form') // application/x-www-form-urlencoded
.send({ username: 'testuser', password: 'secret123' })
.end((err, res) => {
if (err) throw err;
console.log('Login result:', res.body);
});
// PUT request (data update)
const updatedData = {
name: 'Jane Doe',
email: '[email protected]'
};
request
.put('https://api.example.com/users/123')
.send(updatedData)
.set('Authorization', 'Bearer your-jwt-token')
.end((err, res) => {
if (err) throw err;
console.log('User update completed:', res.body);
});
// DELETE request
request
.delete('https://api.example.com/users/123')
.set('Authorization', 'Bearer your-jwt-token')
.end((err, res) => {
if (err) throw err;
if (res.status === 204) {
console.log('User deletion completed');
}
});
// Detailed response information inspection
request
.get('https://api.example.com/test')
.end((err, res) => {
if (err) throw err;
console.log('=== Response Details ===');
console.log(`Status: ${res.status} ${res.statusText}`);
console.log(`Content-Type: ${res.headers['content-type']}`);
console.log(`Data size: ${res.headers['content-length']} bytes`);
console.log(`Response time: ${res.duration}ms`);
console.log(`Request URL: ${res.request.url}`);
console.log(`Request method: ${res.request.method}`);
});
Promise and async/await Asynchronous Processing
const request = require('superagent');
// Processing using Promise chain
request
.get('https://api.example.com/users')
.then(res => {
console.log('User fetch successful:', res.body);
return res.body;
})
.then(users => {
console.log(`Total users: ${users.length}`);
return users.filter(user => user.active);
})
.then(activeUsers => {
console.log(`Active users: ${activeUsers.length}`);
})
.catch(err => {
console.error('Error:', err.message);
if (err.response) {
console.error('Status:', err.response.status);
console.error('Error body:', err.response.body);
}
});
// Processing using async/await
async function fetchUserData() {
try {
// Fetch user list
const usersResponse = await request
.get('https://api.example.com/users')
.query({ active: true, limit: 50 })
.set('Authorization', 'Bearer your-token');
console.log(`Active users: ${usersResponse.body.length} people`);
// Fetch detailed information for each user concurrently
const userDetails = await Promise.all(
usersResponse.body.slice(0, 5).map(async (user) => {
const detailResponse = await request
.get(`https://api.example.com/users/${user.id}`)
.set('Authorization', 'Bearer your-token');
return detailResponse.body;
})
);
console.log('Detail fetch completed:', userDetails);
// Create new user
const newUser = await request
.post('https://api.example.com/users')
.send({
name: 'New User',
email: '[email protected]',
department: 'engineering'
})
.set('Authorization', 'Bearer your-token');
console.log('New user created:', newUser.body);
return newUser.body;
} catch (error) {
console.error('User data processing error:', error.message);
// Error handling
if (error.response) {
console.error(`HTTP error: ${error.response.status}`);
console.error('Error response:', error.response.body);
} else if (error.code === 'ECONNREFUSED') {
console.error('Connection to server was refused');
} else if (error.timeout) {
console.error('Request timed out');
}
throw error;
}
}
// Function execution
fetchUserData()
.then(result => console.log('Processing completed:', result))
.catch(err => console.error('Final error:', err.message));
// Concurrent data fetching from multiple API endpoints
async function fetchDashboardData() {
try {
console.log('Dashboard data fetch started...');
const [usersRes, postsRes, statsRes] = await Promise.all([
request.get('https://api.example.com/users').set('Authorization', 'Bearer token'),
request.get('https://api.example.com/posts').set('Authorization', 'Bearer token'),
request.get('https://api.example.com/stats').set('Authorization', 'Bearer token')
]);
const dashboardData = {
users: usersRes.body,
posts: postsRes.body,
statistics: statsRes.body,
loadTime: Date.now()
};
console.log('Dashboard data fetch completed');
return dashboardData;
} catch (error) {
console.error('Dashboard data fetch failed:', error.message);
throw error;
}
}
// Request with retry functionality
async function retryableRequest(url, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Attempt ${attempt}/${maxRetries}: ${url}`);
const response = await request
.get(url)
.timeout({ response: 5000, deadline: 10000 })
.retry(2); // SuperAgent built-in retry functionality
console.log(`Success: ${response.status}`);
return response.body;
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
console.error('Maximum attempts reached');
throw error;
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
console.log(`Waiting ${delay}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Advanced Configuration and Customization (Headers, Authentication, Timeout, etc.)
const request = require('superagent');
// Custom headers and request configuration
request
.get('https://api.example.com/data')
.set('User-Agent', 'MyApp/2.0 (SuperAgent)')
.set('Accept', 'application/json')
.set('Accept-Language', 'en-US,ja-JP;q=0.8')
.set('X-API-Version', 'v2.1')
.set('X-Request-ID', `req-${Date.now()}`)
.set('Cache-Control', 'no-cache')
.end((err, res) => {
if (err) throw err;
console.log('Request headers:', res.request.header);
console.log('Response headers:', res.headers);
});
// Basic authentication
request
.get('https://api.example.com/private')
.auth('username', 'password') // Basic authentication
.end((err, res) => {
if (err) throw err;
console.log('Authenticated data:', res.body);
});
// Bearer Token authentication
request
.get('https://api.example.com/protected')
.set('Authorization', 'Bearer your-jwt-token-here')
.end((err, res) => {
if (err) throw err;
console.log('Protected resource:', res.body);
});
// API Key authentication
request
.get('https://api.example.com/service')
.set('X-API-Key', 'your-api-key-here')
.set('X-Secret-Key', 'your-secret-key')
.end((err, res) => {
if (err) throw err;
console.log('API key authentication successful:', res.body);
});
// Timeout configuration
request
.get('https://api.example.com/slow-endpoint')
.timeout({
response: 5000, // 5 seconds for server response
deadline: 10000 // 10 seconds for entire request
})
.end((err, res) => {
if (err) {
if (err.timeout) {
console.error('Timeout error:', err.message);
} else {
console.error('Other error:', err.message);
}
return;
}
console.log('Completed within response time:', res.body);
});
// Proxy configuration
request
.get('https://api.example.com/data')
.proxy('http://proxy.company.com:8080')
.end((err, res) => {
if (err) throw err;
console.log('Accessed via proxy:', res.body);
});
// Cookie configuration
request
.get('https://api.example.com/user-data')
.set('Cookie', 'session_id=abc123; user_pref=dark_mode; lang=en')
.end((err, res) => {
if (err) throw err;
console.log('Request with cookies:', res.body);
console.log('Response cookies:', res.headers['set-cookie']);
});
// SSL/TLS configuration (Node.js environment)
const fs = require('fs');
// Using client certificate
request
.get('https://secure-api.example.com/data')
.cert(fs.readFileSync('./client-cert.pem'))
.key(fs.readFileSync('./client-key.pem'))
.ca(fs.readFileSync('./ca-cert.pem'))
.end((err, res) => {
if (err) throw err;
console.log('Client certificate authentication successful:', res.body);
});
// Disable SSL certificate verification (development environment only)
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
request
.get('https://self-signed.example.com/api')
.end((err, res) => {
if (err) throw err;
console.log('Access to self-signed certificate site:', res.body);
});
// Redirect control
request
.get('https://api.example.com/redirect-endpoint')
.redirects(5) // Maximum 5 redirects
.end((err, res) => {
if (err) throw err;
console.log('Final URL:', res.request.url);
console.log('Redirect count:', res.redirects.length);
});
// Custom parser configuration
request
.get('https://api.example.com/xml-data')
.set('Accept', 'application/xml')
.parse((res, callback) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
// Custom XML parse logic
const parsedData = { raw: data, parsed: true };
callback(null, parsedData);
} catch (err) {
callback(err, null);
}
});
})
.end((err, res) => {
if (err) throw err;
console.log('Custom parse result:', res.body);
});
// Response compression support
request
.get('https://api.example.com/large-data')
.set('Accept-Encoding', 'gzip, deflate')
.buffer(true) // Buffer response
.parse(request.parse.json)
.end((err, res) => {
if (err) throw err;
console.log('Compressed data received:', res.body);
});
Error Handling and Retry Functionality
const request = require('superagent');
// Comprehensive error handling
function handleRequest(url, options = {}) {
return new Promise((resolve, reject) => {
request
.get(url)
.set(options.headers || {})
.timeout(options.timeout || 10000)
.end((err, res) => {
if (err) {
// Detailed processing by error type
if (err.timeout) {
console.error(`Timeout error: ${url}`);
console.error(`Configured timeout: ${options.timeout || 10000}ms`);
reject(new Error('REQUEST_TIMEOUT'));
} else if (err.code === 'ECONNREFUSED') {
console.error(`Connection refused: ${url}`);
reject(new Error('CONNECTION_REFUSED'));
} else if (err.code === 'ENOTFOUND') {
console.error(`DNS error: ${url}`);
reject(new Error('DNS_ERROR'));
} else if (err.status >= 400 && err.status < 500) {
console.error(`Client error: ${err.status} - ${url}`);
console.error('Error response:', err.response?.body);
reject(new Error(`CLIENT_ERROR_${err.status}`));
} else if (err.status >= 500) {
console.error(`Server error: ${err.status} - ${url}`);
console.error('Error response:', err.response?.body);
reject(new Error(`SERVER_ERROR_${err.status}`));
} else {
console.error(`Unknown error: ${url}`, err.message);
reject(err);
}
} else {
resolve(res);
}
});
});
}
// Usage example
async function safeApiCall() {
try {
const response = await handleRequest('https://api.example.com/data', {
headers: { 'Authorization': 'Bearer token' },
timeout: 15000
});
console.log('Success:', response.body);
} catch (error) {
switch (error.message) {
case 'REQUEST_TIMEOUT':
console.log('Request timed out. Please try again later.');
break;
case 'CONNECTION_REFUSED':
console.log('Server is unavailable. Please contact system administrator.');
break;
case 'DNS_ERROR':
console.log('Please check your network connection.');
break;
default:
console.log('Unexpected error occurred:', error.message);
}
}
}
// SuperAgent built-in retry functionality
request
.get('https://api.example.com/unstable')
.retry(3) // Maximum 3 retries
.end((err, res) => {
if (err) {
console.error('Failed after 3 retries:', err.message);
} else {
console.log('Success after retry:', res.body);
}
});
// Custom retry logic
async function retryRequest(url, maxRetries = 3, backoffFactor = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`Attempt ${attempt}/${maxRetries}: ${url}`);
const response = await new Promise((resolve, reject) => {
request
.get(url)
.timeout({ response: 5000, deadline: 10000 })
.end((err, res) => {
if (err) reject(err);
else resolve(res);
});
});
console.log(`Success: ${response.status}`);
return response.body;
} catch (error) {
console.log(`Attempt ${attempt} failed:`, error.message);
// Stop immediately for fatal errors
if (error.status === 401 || error.status === 403 || error.status === 404) {
console.error('Fatal error, stopping:', error.status);
throw error;
}
if (attempt === maxRetries) {
console.error('Maximum attempts reached');
throw error;
}
// Wait with exponential backoff
const delay = backoffFactor * Math.pow(2, attempt - 1);
console.log(`Waiting ${delay}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Error monitoring and logging
const errorLogger = {
log: (error, url, method = 'GET') => {
const logEntry = {
timestamp: new Date().toISOString(),
url: url,
method: method,
error: error.message,
status: error.status,
responseTime: error.response?.duration || null,
stack: error.stack
};
console.error('API Error Log:', JSON.stringify(logEntry, null, 2));
// In actual production, send to external log service
// await sendToLogService(logEntry);
}
};
// Request with logging
async function loggedRequest(method, url, data = null) {
const startTime = Date.now();
try {
let req = request[method.toLowerCase()](url);
if (data) {
req = req.send(data);
}
const response = await req;
const responseTime = Date.now() - startTime;
console.log(`Success: ${method} ${url} - ${response.status} (${responseTime}ms)`);
return response.body;
} catch (error) {
const responseTime = Date.now() - startTime;
error.responseTime = responseTime;
errorLogger.log(error, url, method);
throw error;
}
}
// Usage example
async function apiOperations() {
try {
// Normal request
const users = await loggedRequest('GET', 'https://api.example.com/users');
// Request with retry
const unstableData = await retryRequest('https://api.example.com/unstable', 3, 500);
// Create new (with error logging)
const newUser = await loggedRequest('POST', 'https://api.example.com/users', {
name: 'Test User',
email: '[email protected]'
});
console.log('All operations successful');
return { users, unstableData, newUser };
} catch (error) {
console.error('Error during API operations:', error.message);
throw error;
}
}
File Upload and Streaming
const request = require('superagent');
const fs = require('fs');
const path = require('path');
// File upload (multipart)
function uploadFile(filePath, uploadUrl, additionalFields = {}) {
return new Promise((resolve, reject) => {
const fileName = path.basename(filePath);
request
.post(uploadUrl)
.field('description', additionalFields.description || 'Uploaded file')
.field('category', additionalFields.category || 'general')
.field('public', additionalFields.public || 'false')
.attach('file', filePath, fileName)
.set('Authorization', 'Bearer your-upload-token')
.on('progress', (event) => {
if (event.direction === 'upload') {
const progress = (event.loaded / event.total) * 100;
console.log(`Upload progress: ${progress.toFixed(1)}%`);
}
})
.end((err, res) => {
if (err) {
console.error('File upload error:', err.message);
reject(err);
} else {
console.log('File upload completed:', res.body);
resolve(res.body);
}
});
});
}
// Usage example
async function uploadExample() {
try {
const result = await uploadFile('./document.pdf', 'https://api.example.com/upload', {
description: 'Important document',
category: 'documents',
public: 'false'
});
console.log('Upload result:', result);
console.log(`File ID: ${result.fileId}`);
console.log(`Download URL: ${result.downloadUrl}`);
} catch (error) {
console.error('File upload failed:', error.message);
}
}
// Concurrent upload of multiple files
async function uploadMultipleFiles(files, uploadUrl) {
const uploadPromises = files.map(async (filePath, index) => {
try {
console.log(`File ${index + 1}/${files.length} upload started: ${filePath}`);
const result = await uploadFile(filePath, uploadUrl, {
description: `Batch upload ${index + 1}`,
order: index + 1
});
console.log(`File ${index + 1} completed:`, result.fileName);
return result;
} catch (error) {
console.error(`File ${index + 1} failed:`, error.message);
return { error: error.message, file: filePath };
}
});
const results = await Promise.all(uploadPromises);
const successful = results.filter(r => !r.error);
const failed = results.filter(r => r.error);
console.log(`\n=== Upload Results ===`);
console.log(`Successful: ${successful.length} files`);
console.log(`Failed: ${failed.length} files`);
if (failed.length > 0) {
console.log('Failed files:');
failed.forEach(f => console.log(` ${f.file}: ${f.error}`));
}
return { successful, failed };
}
// Direct binary data transmission
function uploadBinaryData(binaryData, fileName, uploadUrl) {
return new Promise((resolve, reject) => {
request
.post(uploadUrl)
.set('Content-Type', 'application/octet-stream')
.set('Content-Disposition', `attachment; filename="${fileName}"`)
.set('Authorization', 'Bearer your-token')
.send(binaryData) // Buffer or stream
.end((err, res) => {
if (err) reject(err);
else resolve(res.body);
});
});
}
// File download
function downloadFile(fileUrl, outputPath) {
return new Promise((resolve, reject) => {
const writeStream = fs.createWriteStream(outputPath);
request
.get(fileUrl)
.set('Authorization', 'Bearer your-download-token')
.on('response', (res) => {
const fileSize = parseInt(res.headers['content-length'], 10);
console.log(`Download started: ${fileSize} bytes`);
})
.on('progress', (event) => {
if (event.direction === 'download' && event.total) {
const progress = (event.loaded / event.total) * 100;
console.log(`Download progress: ${progress.toFixed(1)}%`);
}
})
.pipe(writeStream)
.on('finish', () => {
console.log(`Download completed: ${outputPath}`);
resolve(outputPath);
})
.on('error', (err) => {
console.error('Download error:', err.message);
reject(err);
});
});
}
// Streaming upload
function streamUpload(readableStream, uploadUrl, fileName) {
return new Promise((resolve, reject) => {
request
.post(uploadUrl)
.field('filename', fileName)
.field('timestamp', new Date().toISOString())
.attach('stream', readableStream, fileName)
.set('Authorization', 'Bearer your-token')
.on('progress', (event) => {
if (event.direction === 'upload' && event.total) {
const progress = (event.loaded / event.total) * 100;
console.log(`Stream upload: ${progress.toFixed(1)}%`);
}
})
.end((err, res) => {
if (err) reject(err);
else resolve(res.body);
});
});
}
// Usage example: Streaming upload of large files
async function streamLargeFile() {
try {
const filePath = './large-file.zip';
const readStream = fs.createReadStream(filePath);
console.log('Streaming upload started...');
const result = await streamUpload(
readStream,
'https://api.example.com/stream-upload',
'large-file.zip'
);
console.log('Streaming upload completed:', result);
} catch (error) {
console.error('Streaming upload failed:', error.message);
}
}
Plugin and Middleware Integration
const request = require('superagent');
// Creating plugin functions
function authPlugin(token) {
return function(req) {
req.set('Authorization', `Bearer ${token}`);
return req;
};
}
function loggingPlugin() {
return function(req) {
const startTime = Date.now();
req.on('response', (res) => {
const duration = Date.now() - startTime;
console.log(`${req.method} ${req.url} - ${res.status} (${duration}ms)`);
});
req.on('error', (err) => {
const duration = Date.now() - startTime;
console.log(`${req.method} ${req.url} - ERROR: ${err.message} (${duration}ms)`);
});
return req;
};
}
function retryPlugin(maxRetries = 3) {
return function(req) {
const originalEnd = req.end;
req.end = function(callback) {
let attempts = 0;
const attemptRequest = () => {
attempts++;
console.log(`Attempt ${attempts}/${maxRetries + 1}`);
originalEnd.call(this, (err, res) => {
if (err && attempts <= maxRetries && shouldRetry(err)) {
console.log(`Retry ${attempts}/${maxRetries}: ${err.message}`);
setTimeout(attemptRequest, 1000 * attempts); // Progressive delay
} else {
callback(err, res);
}
});
};
attemptRequest();
};
return req;
};
function shouldRetry(err) {
return err.status >= 500 || err.code === 'ECONNRESET' || err.timeout;
}
}
// Custom middleware
function apiBasePlugin(baseUrl, version = 'v1') {
return function(req) {
// Convert relative URLs to absolute URLs
if (!req.url.startsWith('http')) {
req.url = `${baseUrl}/${version}/${req.url.replace(/^\//, '')}`;
}
// Set default headers
req.set('Accept', 'application/json');
req.set('Content-Type', 'application/json');
req.set('User-Agent', 'MyApp/1.0 (SuperAgent)');
return req;
};
}
// API client using plugins
class ApiClient {
constructor(baseUrl, token, options = {}) {
this.baseUrl = baseUrl;
this.token = token;
this.options = {
version: 'v1',
timeout: 10000,
retries: 3,
logging: true,
...options
};
}
request(method, endpoint) {
let req = request[method](endpoint);
// Apply plugin chain
req = req.use(apiBasePlugin(this.baseUrl, this.options.version));
if (this.token) {
req = req.use(authPlugin(this.token));
}
if (this.options.logging) {
req = req.use(loggingPlugin());
}
if (this.options.retries > 0) {
req = req.use(retryPlugin(this.options.retries));
}
req = req.timeout(this.options.timeout);
return req;
}
get(endpoint) {
return this.request('get', endpoint);
}
post(endpoint, data) {
return this.request('post', endpoint).send(data);
}
put(endpoint, data) {
return this.request('put', endpoint).send(data);
}
delete(endpoint) {
return this.request('delete', endpoint);
}
}
// Usage example
const apiClient = new ApiClient('https://api.example.com', 'your-jwt-token', {
version: 'v2',
timeout: 15000,
retries: 5,
logging: true
});
// Requests with automatically applied plugins
async function useApiClient() {
try {
// GET request
const users = await new Promise((resolve, reject) => {
apiClient.get('users')
.query({ active: true, limit: 50 })
.end((err, res) => {
if (err) reject(err);
else resolve(res.body);
});
});
console.log('User list:', users);
// POST request
const newUser = await new Promise((resolve, reject) => {
apiClient.post('users', {
name: 'Plugin Test User',
email: '[email protected]'
}).end((err, res) => {
if (err) reject(err);
else resolve(res.body);
});
});
console.log('New user:', newUser);
} catch (error) {
console.error('API client error:', error.message);
}
}
// Global plugin configuration
const globalPlugin = function(req) {
// Common settings applied to all requests
req.set('X-Client-Version', '1.0.0');
req.set('X-Timestamp', new Date().toISOString());
// Request start log
console.log(`[REQUEST] ${req.method} ${req.url}`);
return req;
};
// Apply plugin to all SuperAgent requests
request.use = request.use || [];
request.use.push(globalPlugin);
// Express.js middleware integration example
function createExpressApiHandler(apiBaseUrl, token) {
return async (req, res, next) => {
try {
const apiResponse = await new Promise((resolve, reject) => {
request
.get(`${apiBaseUrl}${req.path}`)
.query(req.query)
.set('Authorization', `Bearer ${token}`)
.use(loggingPlugin())
.end((err, apiRes) => {
if (err) reject(err);
else resolve(apiRes);
});
});
res.json(apiResponse.body);
} catch (error) {
console.error('API proxy error:', error.message);
res.status(error.status || 500).json({
error: 'API request failed',
message: error.message
});
}
};
}
// Usage with Express.js
// app.get('/api/*', createExpressApiHandler('https://external-api.com', 'token'));