node-fetch
Fetch API polyfill for Node.js TypeScript environments. Provides same interface as browser's Fetch API with TypeScript type definitions. Enables code sharing and portability, offering consistent development experience in full-stack TypeScript development.
Library
node-fetch
Overview
node-fetch is developed as "a lightweight module that brings the Fetch API to Node.js" - a library that enables browser-standard Fetch API in Node.js environments. Providing consistent HTTP communication with the same API as browser environments, Promise-based simple API, streaming support, and lightweight design. As of 2025, while Node.js 18+ includes native Fetch API, node-fetch continues to be used in many projects due to its proven track record and rich customization options in Node.js environments.
Details
node-fetch 2025 edition faces a major transition period with Node.js native Fetch API support, but continues to provide value in specific use cases leveraging stability in legacy projects, custom agent support, integration with Node.js Streams, and advanced configuration options. With ESM support, TypeScript type definitions, AbortController support, and FormData processing, it adheres to modern web standards. As a library positioned to contribute to code sharing and maintainability improvement in full-stack development through unified APIs between browser and server.
Key Features
- Fetch API Compliance: Identical interface to browser-standard Fetch API
- Streaming Support: Efficient data processing with Node.js Readable streams
- Lightweight Design: Minimal dependencies with lightweight implementation
- Custom Agent: Detailed network control through HTTP/HTTPS agents
- ESM/CommonJS Support: Flexible module system support
- TypeScript Support: Enhanced development experience with complete type definitions
Pros and Cons
Pros
- Unified Fetch API experience between browser and Node.js
- Lightweight with minimal dependencies
- Excellent integration with Node.js Streams
- Detailed network control through custom HTTP agents
- Reliability through proven track record and stability
- Enhanced development efficiency with complete TypeScript support
Cons
- Reduced necessity with native Fetch API available in Node.js 18+
- Limited support for latest HTTP/2 features
- Basic functionality compared to other feature-rich HTTP clients
- Declining maintenance frequency trend
- Not available in browser environments (Node.js specific)
- Other libraries may be more suitable for complex authentication processes
Reference Pages
Code Examples
Installation and Basic Setup
# Install latest node-fetch (v3.x)
npm install node-fetch
# Install v2 series (CommonJS support)
npm install node-fetch@2
# TypeScript type definitions (built-in for v3)
npm install @types/node-fetch --save-dev # For v2
# Check Node.js version (v12.20.0+ recommended)
node --version
// ES6 Modules (v3 recommended)
import fetch from 'node-fetch';
// CommonJS (v2 or dynamic import)
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
// v2 series CommonJS
const fetch = require('node-fetch');
// Global fetch polyfill (ESM)
import fetch, {
Blob,
blobFrom,
blobFromSync,
File,
fileFrom,
fileFromSync,
FormData,
Headers,
Request,
Response,
} from 'node-fetch'
if (!globalThis.fetch) {
globalThis.fetch = fetch
globalThis.Headers = Headers
globalThis.Request = Request
globalThis.Response = Response
}
Basic Requests (GET/POST/PUT/DELETE)
import fetch from 'node-fetch';
// Basic GET request
async function basicGetRequest() {
try {
const response = await fetch('https://api.example.com/users', {
headers: {
'Accept': 'application/json',
'User-Agent': 'MyApp/1.0 (node-fetch)'
}
});
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
console.log('User data:', data);
return data;
} catch (error) {
console.error('GET request error:', error.message);
throw error;
}
}
// Fetch plain text/HTML
async function fetchText() {
try {
const response = await fetch('https://example.com/');
const body = await response.text();
console.log('HTML content:', body);
return body;
} catch (error) {
console.error('Text fetch error:', error.message);
}
}
// Fetch JSON data
async function fetchJsonData() {
try {
const response = await fetch('https://api.github.com/users/github');
const data = await response.json();
console.log('GitHub user info:', data);
return data;
} catch (error) {
console.error('JSON fetch error:', error.message);
}
}
// Simple POST request
async function simplePostRequest() {
try {
const response = await fetch('https://httpbin.org/post', {
method: 'POST',
body: 'a=1&b=2',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
const data = await response.json();
console.log('POST response:', data);
return data;
} catch (error) {
console.error('POST error:', error.message);
}
}
// POST request with JSON
async function postJsonRequest() {
try {
const requestData = {
name: 'John Doe',
email: '[email protected]',
age: 30,
department: 'Engineering'
};
const response = await fetch('https://api.example.com/users', {
method: 'POST',
body: JSON.stringify(requestData),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-jwt-token'
}
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Creation failed: ${response.status} - ${errorText}`);
}
const newUser = await response.json();
console.log('New user created:', newUser);
return newUser;
} catch (error) {
console.error('User creation error:', error.message);
throw error;
}
}
// PUT request (update)
async function putRequest() {
try {
const updateData = {
name: 'Jane Doe',
email: '[email protected]',
department: 'Product Development'
};
const response = await fetch('https://api.example.com/users/123', {
method: 'PUT',
body: JSON.stringify(updateData),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-jwt-token'
}
});
if (response.status === 200) {
const updatedUser = await response.json();
console.log('User updated successfully:', updatedUser);
return updatedUser;
} else {
throw new Error(`Update failed: ${response.status}`);
}
} catch (error) {
console.error('Update error:', error.message);
throw error;
}
}
// DELETE request
async function deleteRequest() {
try {
const response = await fetch('https://api.example.com/users/123', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer your-jwt-token'
}
});
if (response.status === 204) {
console.log('User deleted successfully');
return true;
} else {
throw new Error(`Delete failed: ${response.status}`);
}
} catch (error) {
console.error('Delete error:', error.message);
return false;
}
}
// Form data submission using URLSearchParams
async function postFormData() {
try {
const params = new URLSearchParams();
params.append('username', 'testuser');
params.append('password', 'secret123');
params.append('remember', 'true');
const response = await fetch('https://api.example.com/login', {
method: 'POST',
body: params
});
const result = await response.json();
console.log('Login result:', result);
return result;
} catch (error) {
console.error('Form submission error:', error.message);
}
}
// Response metadata retrieval
async function responseMetadata() {
try {
const response = await fetch('https://api.example.com/status');
console.log('Success:', response.ok);
console.log('Status code:', response.status);
console.log('Status text:', response.statusText);
console.log('All headers:', response.headers.raw());
console.log('Content-Type:', response.headers.get('content-type'));
if (response.ok) {
const data = await response.json();
return data;
}
} catch (error) {
console.error('Metadata retrieval error:', error.message);
}
}
// Usage examples
basicGetRequest();
fetchJsonData();
postJsonRequest();
Advanced Configuration and Customization (Headers, Authentication, Timeout, etc.)
import fetch from 'node-fetch';
import http from 'node:http';
import https from 'node:https';
// Custom agent setup
const httpAgent = new http.Agent({
keepAlive: true,
maxSockets: 10,
timeout: 10000
});
const httpsAgent = new https.Agent({
keepAlive: true,
maxSockets: 10,
timeout: 10000,
rejectUnauthorized: true
});
// Advanced headers and authentication
async function advancedHeaders() {
try {
const response = await fetch('https://api.example.com/protected', {
method: 'GET',
headers: {
'Authorization': 'Bearer your-jwt-token',
'Accept': 'application/json',
'User-Agent': 'MyApp/1.0 (node-fetch)',
'X-API-Version': 'v2',
'X-Request-ID': generateRequestId(),
'Accept-Language': 'en-US,ja-JP;q=0.9',
'Cache-Control': 'no-cache'
},
timeout: 10000,
// Custom agent function
agent: function(parsedURL) {
if (parsedURL.protocol === 'http:') {
return httpAgent;
} else {
return httpsAgent;
}
}
});
console.log('Protected resource accessed successfully');
return await response.json();
} catch (error) {
console.error('Authentication error:', error.message);
throw error;
}
}
// Default options configuration
const defaultOptions = {
method: 'GET',
headers: {
'User-Agent': 'MyApp/1.0 (node-fetch)',
'Accept': 'application/json'
},
redirect: 'follow', // Automatic redirect following
follow: 20, // Maximum redirect count
compress: true, // gzip/deflate compression support
size: 0, // Maximum response body size (0=unlimited)
agent: null, // HTTP agent
highWaterMark: 16384, // Stream internal buffer size
insecureHTTPParser: false // Allow invalid HTTP headers
};
// SSL/TLS configuration
async function sslConfiguration() {
try {
const response = await fetch('https://secure-api.example.com/data', {
agent: new https.Agent({
rejectUnauthorized: true, // Enable SSL certificate verification
ca: [/* CA certificates */], // CA certificate configuration
cert: '/* client certificate */',
key: '/* private key */',
passphrase: 'certificate-passphrase'
})
});
console.log('SSL communication successful');
return await response.json();
} catch (error) {
console.error('SSL configuration error:', error.message);
}
}
// Proxy configuration
async function proxyConfiguration() {
try {
const ProxyAgent = await import('proxy-agent');
const response = await fetch('https://api.example.com/data', {
agent: new ProxyAgent.ProxyAgent('http://proxy.example.com:8080'),
headers: {
'User-Agent': 'MyApp via Proxy'
}
});
console.log('Response received via proxy');
return await response.json();
} catch (error) {
console.error('Proxy error:', error.message);
}
}
// Cookie handling
async function cookieHandling() {
try {
// Send cookies
const response = await fetch('https://api.example.com/session-data', {
headers: {
'Cookie': 'session_id=abc123; user_pref=dark_mode'
}
});
// Get cookies from response
const setCookieHeader = response.headers.get('set-cookie');
if (setCookieHeader) {
console.log('Received cookies:', setCookieHeader);
}
// Get multiple Set-Cookie headers
const rawHeaders = response.headers.raw();
const setCookies = rawHeaders['set-cookie'];
if (setCookies) {
console.log('All cookie headers:', setCookies);
}
return await response.json();
} catch (error) {
console.error('Cookie handling error:', error.message);
}
}
// Redirect control
async function redirectControl() {
try {
// Manual redirect handling
const response = await fetch('https://httpbin.org/status/301', {
redirect: 'manual'
});
if (response.status === 301 || response.status === 302) {
const locationURL = new URL(response.headers.get('location'), response.url);
console.log('Redirect target:', locationURL.href);
// Manually request redirect target
const response2 = await fetch(locationURL, { redirect: 'manual' });
console.log('Status after redirect:', response2.status);
return await response2.json();
}
} catch (error) {
console.error('Redirect handling error:', error.message);
}
}
// Streaming configuration
async function streamingConfiguration() {
try {
const response = await fetch('https://api.example.com/large-dataset', {
highWaterMark: 1024 * 1024, // 1MB buffer
compress: true
});
if (!response.ok) {
throw new Error(`Streaming error: ${response.statusText}`);
}
// Create response clone (for parallel processing)
const clonedResponse = response.clone();
// Process response in parallel
const [jsonResult, textResult] = await Promise.all([
response.json(),
clonedResponse.text()
]);
console.log('JSON result:', jsonResult);
console.log('Text length:', textResult.length);
} catch (error) {
console.error('Streaming configuration error:', error.message);
}
}
function generateRequestId() {
return 'req-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
}
// Usage examples
advancedHeaders();
sslConfiguration();
cookieHandling();
Error Handling and Retry Functionality
import fetch, { AbortError } from 'node-fetch';
// Custom error class
class HTTPResponseError extends Error {
constructor(response) {
super(`HTTP Error Response: ${response.status} ${response.statusText}`);
this.response = response;
}
}
// Status check function
const checkStatus = response => {
if (response.ok) {
return response;
} else {
throw new HTTPResponseError(response);
}
};
// Comprehensive error handling
async function comprehensiveErrorHandling() {
try {
const response = await fetch('https://api.example.com/users', {
timeout: 10000,
headers: {
'Authorization': 'Bearer your-jwt-token'
}
});
checkStatus(response);
return await response.json();
} catch (error) {
if (error instanceof HTTPResponseError) {
const status = error.response.status;
const errorBody = await error.response.text();
console.error(`HTTP Error: ${status}`);
switch (status) {
case 400:
console.error('Bad Request: Please check request parameters');
break;
case 401:
console.error('Unauthorized: Invalid authentication credentials');
// Execute token refresh
return await refreshTokenAndRetry();
case 403:
console.error('Forbidden: Insufficient permissions');
break;
case 404:
console.error('Not Found: Resource does not exist');
break;
case 429:
console.error('Rate Limited: Please try again later');
const retryAfter = error.response.headers.get('retry-after');
if (retryAfter) {
console.error(`Retry available after: ${retryAfter} seconds`);
}
break;
case 500:
console.error('Internal Server Error: Server-side issue');
break;
case 502:
console.error('Bad Gateway: Server temporarily unavailable');
break;
case 503:
console.error('Service Unavailable: Server overloaded');
break;
default:
console.error('Error details:', errorBody);
}
} else if (error instanceof AbortError) {
console.error('Request was cancelled');
} else {
console.error('Network error:', error.message);
}
throw error;
}
}
// Manual retry strategy
async function manualRetryStrategy() {
const maxRetries = 3;
const baseDelay = 1000; // 1 second
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.example.com/unstable-endpoint', {
timeout: 10000
});
checkStatus(response);
return await response.json();
} catch (error) {
const isLastAttempt = attempt === maxRetries;
if (isLastAttempt) {
console.error(`Maximum retry attempts reached: ${error.message}`);
throw error;
}
// Check if error should be retried
const shouldRetry = shouldRetryError(error);
if (!shouldRetry) {
console.error(`Non-retryable error: ${error.message}`);
throw error;
}
// Exponential backoff
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Retry ${attempt + 1}/${maxRetries} - retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Retry determination function
function shouldRetryError(error) {
if (error instanceof AbortError) {
return false; // Usually don't retry timeouts
}
if (error instanceof HTTPResponseError) {
const status = error.response.status;
return [408, 429, 500, 502, 503, 504].includes(status);
}
// Retry network errors
return true;
}
// Progressive failure recovery (failover)
async function progressiveRecovery() {
const endpoints = [
'https://primary-api.example.com/data',
'https://backup-api.example.com/data',
'https://fallback-api.example.com/data'
];
for (let i = 0; i < endpoints.length; i++) {
try {
console.log(`Attempt ${i + 1}: ${endpoints[i]}`);
const response = await fetch(endpoints[i], {
timeout: 5000 + (i * 2000) // Gradually increase timeout
});
checkStatus(response);
console.log(`Success with endpoint ${i + 1}`);
return await response.json();
} catch (error) {
console.log(`Endpoint ${i + 1} failed: ${error.message}`);
if (i === endpoints.length - 1) {
console.error('All endpoints failed');
throw new Error('All endpoints failed');
}
}
}
}
// Partial failure tolerance (parallel requests)
async function partialFailureTolerance() {
const endpoints = [
'https://api.example.com/reliable',
'https://api.example.com/unreliable',
'https://api.example.com/another'
];
const requests = endpoints.map(url =>
fetch(url, { timeout: 3000 })
.then(response => ({ success: true, url, data: response.json() }))
.catch(error => ({ success: false, url, error: error.message }))
);
const results = await Promise.all(requests);
const successful = results.filter(result => result.success);
const failed = results.filter(result => !result.success);
console.log(`Success: ${successful.length}, Failed: ${failed.length}`);
console.log('Failure details:', failed);
return { successful, failed };
}
// Handle network and operational exceptions
async function handleNetworkExceptions() {
try {
await fetch('https://domain.invalid/');
} catch (error) {
console.log('Network error caught:', error.message);
if (error.code === 'ENOTFOUND') {
console.error('DNS resolution failed: Domain does not exist');
} else if (error.code === 'ECONNREFUSED') {
console.error('Connection refused: Server not listening on port');
} else if (error.code === 'ECONNRESET') {
console.error('Connection reset: Server disconnected');
} else {
console.error('Other network error:', error.code);
}
}
}
// Token refresh functionality
async function refreshTokenAndRetry() {
try {
const refreshResponse = await fetch('https://api.example.com/auth/refresh', {
method: 'POST',
body: JSON.stringify({ refresh_token: 'stored-refresh-token' }),
headers: { 'Content-Type': 'application/json' }
});
checkStatus(refreshResponse);
const tokens = await refreshResponse.json();
console.log('Token refresh successful');
// Retry original request with new token
return await fetch('https://api.example.com/users', {
headers: {
'Authorization': `Bearer ${tokens.access_token}`
}
});
} catch (error) {
console.error('Token refresh failed:', error.message);
throw error;
}
}
// Usage examples
comprehensiveErrorHandling();
manualRetryStrategy();
progressiveRecovery();
Concurrent Processing and Asynchronous Requests
import fetch from 'node-fetch';
import { createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream';
import { promisify } from 'node:util';
const streamPipeline = promisify(pipeline);
// Basic parallel requests
async function basicParallelRequests() {
const startTime = Date.now();
try {
const [users, posts, comments, categories] = await Promise.all([
fetch('https://api.example.com/users'),
fetch('https://api.example.com/posts'),
fetch('https://api.example.com/comments'),
fetch('https://api.example.com/categories')
]);
const endTime = Date.now();
console.log(`Parallel execution time: ${endTime - startTime}ms`);
// Parallel JSON parsing
const [usersData, postsData, commentsData, categoriesData] = await Promise.all([
users.json(),
posts.json(),
comments.json(),
categories.json()
]);
return {
users: usersData,
posts: postsData,
comments: commentsData,
categories: categoriesData
};
} catch (error) {
console.error('Parallel request error:', error.message);
throw error;
}
}
// Partial failure tolerance using Promise.allSettled
async function parallelWithPartialFailure() {
const endpoints = [
'https://api.example.com/endpoint1',
'https://api.example.com/endpoint2',
'https://api.example.com/endpoint3',
'https://api.example.com/unreliable-endpoint'
];
const requests = endpoints.map(url => fetch(url, { timeout: 5000 }));
const results = await Promise.allSettled(requests);
const successful = [];
const failed = [];
for (let i = 0; i < results.length; i++) {
const result = results[i];
if (result.status === 'fulfilled') {
try {
const data = await result.value.json();
successful.push({
url: endpoints[i],
data: data
});
} catch (parseError) {
failed.push({
url: endpoints[i],
error: 'JSON parsing error'
});
}
} else {
failed.push({
url: endpoints[i],
error: result.reason.message
});
}
}
console.log(`Success: ${successful.length}, Failed: ${failed.length}`);
return { successful, failed };
}
// Sequential data fetching (pagination)
async function fetchAllPages() {
const allData = [];
let page = 1;
let hasMore = true;
while (hasMore) {
try {
const response = await fetch(`https://api.example.com/paginated-data?page=${page}&limit=20`, {
timeout: 10000
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const pageData = await response.json();
allData.push(...pageData.items);
hasMore = pageData.has_more;
page++;
console.log(`Page ${page - 1} completed: ${pageData.items.length} items`);
// Wait to reduce API load
if (hasMore) {
await new Promise(resolve => setTimeout(resolve, 200));
}
} catch (error) {
console.error(`Page ${page} fetch error: ${error.message}`);
break;
}
}
console.log(`Total ${allData.length} items fetched`);
return allData;
}
// Parallel pagination (high-speed data fetching)
async function parallelPagination() {
try {
// Get total pages from first page
const firstPageResponse = await fetch('https://api.example.com/paginated-data?page=1&limit=20');
const firstPageData = await firstPageResponse.json();
const totalPages = firstPageData.total_pages;
const allData = [...firstPageData.items];
if (totalPages > 1) {
// Fetch remaining pages in parallel
const pagePromises = [];
for (let page = 2; page <= totalPages; page++) {
pagePromises.push(
fetch(`https://api.example.com/paginated-data?page=${page}&limit=20`, {
timeout: 10000
})
);
}
const pageResults = await Promise.allSettled(pagePromises);
for (let i = 0; i < pageResults.length; i++) {
const result = pageResults[i];
if (result.status === 'fulfilled') {
try {
const pageData = await result.value.json();
allData.push(...pageData.items);
} catch (parseError) {
console.error(`Page ${i + 2} JSON parsing error`);
}
} else {
console.error(`Page ${i + 2} failed: ${result.reason.message}`);
}
}
}
console.log(`Parallel fetch completed: ${allData.length} items`);
return allData;
} catch (error) {
console.error('Parallel pagination error:', error.message);
return [];
}
}
// Rate-limited sequential execution
async function rateLimitedRequests(urls, requestsPerSecond = 5) {
const interval = 1000 / requestsPerSecond; // Request interval (milliseconds)
const results = [];
for (let i = 0; i < urls.length; i++) {
const startTime = Date.now();
try {
const response = await fetch(urls[i], { timeout: 5000 });
const data = await response.json();
results.push({
url: urls[i],
success: true,
data: data
});
console.log(`${i + 1}/${urls.length} completed: ${urls[i]}`);
} catch (error) {
results.push({
url: urls[i],
success: false,
error: error.message
});
console.error(`${i + 1}/${urls.length} failed: ${urls[i]}`);
}
// Rate limiting wait
if (i < urls.length - 1) {
const elapsed = Date.now() - startTime;
const waitTime = Math.max(0, interval - elapsed);
if (waitTime > 0) {
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
const successCount = results.filter(r => r.success).length;
console.log(`Processing completed: ${successCount}/${urls.length} successful`);
return results;
}
// Concurrency-limited parallel processing
async function concurrencyLimitedRequests(urls, maxConcurrency = 3) {
const results = [];
const executing = [];
for (const url of urls) {
const promise = fetch(url, { timeout: 5000 })
.then(response => response.json())
.then(data => ({ url, success: true, data }))
.catch(error => ({ url, success: false, error: error.message }));
results.push(promise);
if (urls.length >= maxConcurrency) {
executing.push(promise);
if (executing.length >= maxConcurrency) {
await Promise.race(executing);
executing.splice(executing.findIndex(p => p === promise), 1);
}
}
}
const finalResults = await Promise.all(results);
const successCount = finalResults.filter(r => r.success).length;
console.log(`Concurrency-limited processing completed: ${successCount}/${urls.length} successful`);
return finalResults;
}
// Streaming data processing
async function streamingProcessing() {
try {
const response = await fetch('https://api.example.com/stream/data', {
timeout: 60000
});
if (!response.ok) {
throw new Error(`Streaming error: ${response.statusText}`);
}
// Using async iterators in Node.js 14+
let processedChunks = 0;
for await (const chunk of response.body) {
try {
const data = JSON.parse(chunk.toString());
console.log('Processed data:', data);
processedChunks++;
if (processedChunks % 100 === 0) {
console.log(`${processedChunks} chunks processed`);
}
} catch (parseError) {
console.error('Chunk parsing error:', parseError.message);
}
}
console.log(`Streaming processing completed: ${processedChunks} chunks`);
} catch (error) {
console.error('Streaming error:', error.message);
}
}
// File download (streaming)
async function downloadFile() {
try {
const response = await fetch('https://example.com/large-file.zip');
if (!response.ok) {
throw new Error(`Download error: ${response.statusText}`);
}
await streamPipeline(response.body, createWriteStream('./downloaded-file.zip'));
console.log('File download completed');
} catch (error) {
console.error('File download error:', error.message);
}
}
// Usage examples
const sampleUrls = [
'https://api.example.com/data1',
'https://api.example.com/data2',
'https://api.example.com/data3'
];
basicParallelRequests();
parallelWithPartialFailure();
fetchAllPages();
rateLimitedRequests(sampleUrls, 2);
Framework Integration and Practical Examples
// Express.js integration example
import express from 'express';
import fetch from 'node-fetch';
const app = express();
app.use(express.json());
// API proxy endpoint
app.get('/api/proxy/:service/*', async (req, res) => {
try {
const { service } = req.params;
const path = req.params[0];
const serviceUrls = {
'users': 'https://users-api.example.com',
'posts': 'https://posts-api.example.com',
'comments': 'https://comments-api.example.com'
};
const baseUrl = serviceUrls[service];
if (!baseUrl) {
return res.status(404).json({ error: 'Service not found' });
}
const queryString = new URLSearchParams(req.query).toString();
const targetUrl = `${baseUrl}/${path}${queryString ? '?' + queryString : ''}`;
const response = await fetch(targetUrl, {
method: req.method,
headers: {
'Authorization': req.headers.authorization,
'Content-Type': 'application/json'
},
body: req.method !== 'GET' ? JSON.stringify(req.body) : null,
timeout: 10000
});
if (!response.ok) {
return res.status(response.status).json({
error: 'Proxy request failed',
status: response.status
});
}
const data = await response.json();
res.json(data);
} catch (error) {
console.error('Proxy error:', error.message);
res.status(500).json({
error: 'Proxy request failed',
message: error.message
});
}
});
// API client service class
class ApiService {
constructor(baseURL, apiKey) {
this.baseURL = baseURL;
this.apiKey = apiKey;
}
// Common request configuration
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const defaultOptions = {
timeout: 10000,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
'User-Agent': 'Node.js App/1.0'
}
};
const mergedOptions = {
...defaultOptions,
...options,
headers: {
...defaultOptions.headers,
...options.headers
}
};
return await fetch(url, mergedOptions);
}
// Get users
async getUsers(page = 1, limit = 20) {
try {
const response = await this.request(`/users?page=${page}&limit=${limit}`);
if (!response.ok) {
throw new Error(`User fetch failed: ${response.status}`);
}
const data = await response.json();
return {
data: data,
pagination: {
page,
limit,
total: parseInt(response.headers.get('x-total-count') || '0')
}
};
} catch (error) {
console.error('User fetch error:', error.message);
throw error;
}
}
// Create user
async createUser(userData) {
try {
const response = await this.request('/users', {
method: 'POST',
body: JSON.stringify(userData)
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`User creation failed: ${response.status} - ${errorText}`);
}
return await response.json();
} catch (error) {
console.error('User creation error:', error.message);
throw error;
}
}
// Update user
async updateUser(id, userData) {
try {
const response = await this.request(`/users/${id}`, {
method: 'PUT',
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`User update failed: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('User update error:', error.message);
throw error;
}
}
// Delete user
async deleteUser(id) {
try {
const response = await this.request(`/users/${id}`, {
method: 'DELETE'
});
return response.status === 204;
} catch (error) {
console.error('User deletion error:', error.message);
return false;
}
}
}
// FormData and file upload
import { FormData, File, fileFromSync } from 'node-fetch';
async function uploadFile() {
try {
const formData = new FormData();
const httpbin = 'https://httpbin.org/post';
// Add text fields
formData.set('description', 'File upload test');
formData.set('category', 'documents');
// Add file
const fileContent = new Uint8Array([97, 98, 99]); // "abc"
const file = new File([fileContent], 'test.txt', { type: 'text/plain' });
formData.set('file-upload', file, 'uploaded-file.txt');
// Load file from filesystem
// const fileFromDisk = fileFromSync('./input.txt', 'text/plain');
// formData.set('disk-file', fileFromDisk);
const response = await fetch(httpbin, {
method: 'POST',
body: formData
});
const result = await response.json();
console.log('Upload result:', result);
} catch (error) {
console.error('File upload error:', error.message);
}
}
// Custom Blob/File object
async function customBlobUpload() {
try {
const formData = new FormData();
// Custom object (meeting minimum requirements)
const customBlob = {
[Symbol.toStringTag]: 'Blob',
size: 3,
*stream() {
yield new Uint8Array([97, 98, 99]);
},
arrayBuffer() {
return new Uint8Array([97, 98, 99]).buffer;
}
};
formData.append('custom-upload', customBlob, 'custom.txt');
const response = await fetch('https://httpbin.org/post', {
method: 'POST',
body: formData
});
const result = await response.json();
console.log('Custom upload result:', result);
} catch (error) {
console.error('Custom upload error:', error.message);
}
}
// Request cancellation functionality
async function abortableRequest() {
// AbortController (global in Node.js 14.17.0+)
const AbortController = globalThis.AbortController || (await import('abort-controller')).default;
const controller = new AbortController();
// Cancel after 5 seconds
const timeout = setTimeout(() => {
controller.abort();
}, 5000);
try {
const response = await fetch('https://httpbin.org/delay/10', {
signal: controller.signal
});
clearTimeout(timeout);
const data = await response.json();
console.log('Request successful:', data);
} catch (error) {
clearTimeout(timeout);
if (error.name === 'AbortError') {
console.log('Request was aborted');
} else {
console.error('Request error:', error.message);
}
}
}
// Webhook processing (Express.js)
import { Response } from 'node-fetch';
app.post('/webhook', async (req, res) => {
try {
// Parse request body using node-fetch Response class
const formData = await new Response(req, {
headers: req.headers
}).formData();
const allFields = [...formData];
console.log('Received fields:', allFields);
const uploadedFile = formData.get('uploaded-file');
if (uploadedFile) {
const fileBuffer = await uploadedFile.arrayBuffer();
const fileText = await uploadedFile.text();
console.log('File content:', fileText);
}
res.json({ status: 'webhook received successfully' });
} catch (error) {
console.error('Webhook processing error:', error.message);
res.status(500).json({ error: 'webhook processing failed' });
}
});
// Usage examples
const apiService = new ApiService('https://api.example.com', 'your-api-key');
// Application execution example
async function runApplication() {
try {
const users = await apiService.getUsers(1, 10);
console.log('Fetched users:', users);
const newUser = await apiService.createUser({
name: 'New User',
email: '[email protected]'
});
console.log('Created user:', newUser);
await uploadFile();
await abortableRequest();
} catch (error) {
console.error('Application error:', error.message);
}
}
// Express.js server startup
app.listen(3000, () => {
console.log('Server started on port 3000');
});
// Node.js application execution
runApplication();