Node Fetch is a module that adds the Fetch API to Node.js, enabling developers to make HTTP requests the same way they do in a browser. Node Fetch provides a promise-based interface for network operations, which is important for server-side applications that interact with external APIs or services.
Node Fetch connects server-side code with external data sources in Node.js. The module allows developers to fetch data from third-party APIs, communicate with microservices, and retrieve resources for server-side rendering, therefore simplifying these tasks.
Here’s why Node Fetch is important for modern web development:
The module streamlines development processes, maintains clean code, and supports the creation of efficient, scalable applications.
Set up is simple and enables you to use the Fetch API on the server side.
Navigate to your project directory in the terminal and run
```bash
npm init -y
```
This command creates a package.json file, which is essential for managing your project’s dependencies.
Next, run this:
```bash
npm install node-fetch
```
This command adds the node-fetch module to your project.
Then, verify installation by checking the dependencies in your package.json:
```json
{
"dependencies": {
"node-fetch": "^3.3.2"
}
}
```
This step verifies that Node Fetch has been successfully installed as a project dependency.
Now, choose the import method based on your project:
CommonJS
```javascript
const fetch = require('node-fetch');
```
This import statement uses CommonJS syntax.
ES Modules
```javascript
import fetch from 'node-fetch';
```
This import statement uses ES Modules syntax, which requires that your Node.js project use ES Modules.
Import the module as shown above.
```javascript
const fetch = require('node-fetch');
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
This code shows a basic GET request that logs the JSON response.
```javascript
const fetch = require('node-fetch');
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log('Success:', data))
.catch(error => console.error('Error:', error));
```
The code above sends a POST request with a JSON payload, showing how to send data to an API.
The Fetch API replaces XMLHttpRequest for handling HTTP requests more efficiently. Node Fetch brings this API to Node.js, allowing network operations on both the client and server side.
Key features include
Node Fetch supports standard HTTP methods:
1. GET: Retrieve data.
```javascript
fetch('https://api.example.com/users')
.then(response => response.json())
.then(users => console.log(users));
```
The code above retrieves a list of users from an API using a GET request.
2. POST: Create new resources.
```javascript
fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John Doe', email: '[email protected]' })
})
.then(response => response.json())
.then(user => console.log(user));
```
The code above sends a POST request to create a new user, including request headers and body.
3. PUT: Update or create resources.
```javascript
fetch('https://api.example.com/users/1', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Jane Doe', email: '[email protected]' })
})
.then(response => response.json())
.then(updatedUser => console.log(updatedUser));
```
This code shows how to use an HTTP PUT request to update a user resource, also including headers and body.
4. DELETE: Remove resources.
```javascript
fetch('https://api.example.com/users/1', { method: 'DELETE' })
.then(response => {
if (response.ok) {
console.log('User deleted.');
}
})
.catch(error => console.error('Error:', error));
```
The code above shows how to use an HTTP DELETE request to remove a user from the server.
5. HEAD, PATCH, OPTIONS: You can use these methods for specialized tasks.
Proper management of responses and errors is important when building applications.
Now, let’s check the response status using response.ok and response.status.
```javascript
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
This code shows how to check for HTTP error status codes and parse the response as JSON.
Some best practices for handling responses and errors include:
You can customize your HTTP requests with specific headers, authentication, or configurations.
```javascript
const fetch = require('node-fetch');
const options = {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Accept': 'application/json',
'Custom-Header': 'CustomValue'
}
};
fetch('https://api.example.com/data', options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
This code configures request headers, including authorization, content type, and a custom header.
```javascript
const fetch = require('node-fetch');
const userData = { name: 'Jane Doe', email: '[email protected]' };
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData)
};
fetch('https://api.example.com/users', options)
.then(response => response.json())
.then(data => console.log('User Created:', data))
.catch(error => console.error('Error:', error));
```
This code sends a POST request with a JSON payload, showing how to include data in the request body.
```javascript
const fetch = require('node-fetch');
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
fetch('https://api.example.com/slow-endpoint', { signal: controller.signal })
.then(response => response.json())
.then(data => {
clearTimeout(timeout);
console.log(data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.error('Request timed out');
} else {
console.error('Error:', error);
}
});
```
This code shows how to set a timeout for fetch requests using AbortController.
```javascript
const fetch = require('node-fetch');
const options = { method: 'GET', redirect: 'follow' };
fetch('http://api.example.com/redirect', options)
.then(response => {
if (response.redirected) {
console.log('Redirected to:', response.url);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
This code demonstrates how to handle HTTP redirects with Node Fetch.
```javascript
const fetch = require('node-fetch');
const HttpsProxyAgent = require('https-proxy-agent');
const proxyUrl = 'http://proxy.example.com:8080';
const agent = new HttpsProxyAgent(proxyUrl);
const options = { method: 'GET', agent };
fetch('https://api.example.com/data', options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
This code shows how to configure a proxy for your fetch request using the HttpsProxyAgent package.
Node Fetch doesn’t include built-in cookie management, but it can be extended with libraries like tough-cookie and fetch-cookie. Let’s take a look:
```javascript
const fetch = require('node-fetch');
const tough = require('tough-cookie');
const { CookieJar } = tough;
const { default: fetchCookie } = require('fetch-cookie');
const jar = new CookieJar();
const fetchWithCookies = fetchCookie(fetch, jar);
const login = async () => {
const response = await fetchWithCookies('https://api.example.com/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'user', password: 'pass' })
});
return response.json();
};
const fetchProtectedData = async () => {
const response = await fetchWithCookies('https://api.example.com/protected', {
method: 'GET'
});
return response.json();
};
(async () => {
try {
const loginData = await login();
console.log('Logged in:', loginData);
const protectedData = await fetchProtectedData();
console.log('Protected Data:', protectedData);
} catch (error) {
console.error('Error:', error);
}
})();
```
This example uses tough-cookie and fetch-cookie to manage sessions with Node Fetch.
Streaming is important for handling large payloads.
```javascript
const fetch = require('node-fetch');
const fs = require('fs');
const dest = fs.createWriteStream('./large-file.zip');
fetch('https://api.example.com/large-file')
.then(response => {
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.statusText}`);
}
response.body.pipe(dest);
})
.catch(error => console.error('Error:', error));
```
This code streams a response body to a file for efficient handling of large data transfers.
Node Fetch is ideal for interacting with REST APIs and supporting CRUD operations.
```javacript
const fetch = require('node-fetch');
const getProducts = async () => {
try {
const response = await fetch('https://api.example.com/products');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const products = await response.json();
console.log('Products:', products);
} catch (error) {
console.error('Error fetching products:', error);
}
};
getProducts();
```
This code shows how to fetch a list of products from an API endpoint using GET.
```javascript
const fetch = require('node-fetch');
const addProduct = async (product) => {
try {
const response = await fetch('https://api.example.com/products', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(product),
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const newProduct = await response.json();
console.log('New Product Added:', newProduct);
} catch (error) {
console.error('Error adding product:', error);
}
};
const product = { name: 'Wireless Mouse', price: 29.99, category: 'Electronics' };
addProduct(product);
```
The code above shows how to create a new product resource using a POST request, including the required headers and body.
```javascript
const fetch = require('node-fetch');
const updateProduct = async (productId, updatedData) => {
try {
const response = await fetch(`https://api.example.com/products/${productId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(updatedData),
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const updatedProduct = await response.json();
console.log('Product Updated:', updatedProduct);
} catch (error) {
console.error('Error updating product:', error);
}
};
const updatedData = { price: 24.99, stock: 150 };
updateProduct(101, updatedData);
```
This code example uses a PUT request to update a product; headers and body are provided.
```javascript
const fetch = require('node-fetch');
const deleteProduct = async (productId) => {
try {
const response = await fetch(`https://api.example.com/products/${productId}`, {
method: 'DELETE',
});
if (response.ok) {
console.log(`Product with ID ${productId} deleted.`);
} else {
throw new Error(`HTTP error! Status: ${response.status}`);
}
} catch (error) {
console.error('Error deleting product:', error);
}
};
deleteProduct(101);
```
The code above shows how to delete a specific product using a DELETE request.
Node Fetch can easily retrieve data from various external APIs. Here are some examples:
const fetch = require('node-fetch');
const getWeather = async (city) => {
const apiKey = 'YOUR_OPENWEATHERMAP_API_KEY';
const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const weatherData = await response.json();
console.log(`Weather in ${city}:`, weatherData);
} catch (error) {
console.error('Error fetching weather data:', error);
}
};
getWeather('New York');
```
The code above uses an external API to get the weather data of a specified city.
```javascript
const fetch = require('node-fetch');
const getStockPrice = async (symbol) => {
const apiKey = 'YOUR_ALPHAVANTAGE_API_KEY';
const url = `https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=${symbol}&apikey=${apiKey}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const stockData = await response.json();
console.log(`Stock Price for ${symbol}:`, stockData['Global Quote']);
} catch (error) {
console.error('Error fetching stock data:', error);
}
};
getStockPrice('AAPL');
```
The code above uses an external API to get the stock price of a company using an API key.
Node Fetch is important for server-side rendering (SSR) by fetching necessary data to render full HTML pages.
```javascript
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.set('view engine', 'ejs');
app.get('/dashboard', async (req, res) => {
try {
const response = await fetch('https://api.example.com/user/data');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const userData = await response.json();
res.render('dashboard', { user: userData });
} catch (error) {
console.error('Error fetching user data:', error);
res.status(500).send('Internal Server Error');
}
});
app.listen(3000, () => console.log('Server is running on port 3000'));
```
The code above uses Node Fetch to retrieve data before rendering a page using EJS and Express.js.
```javascript
const express = require('express');
const fetch = require('node-fetch');
const app = express();
app.get('/', async (req, res) => {
try {
const response = await fetch('https://api.example.com/homepage/content');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const content = await response.json();
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Home Page</title>
<meta name="description" content="${content.metaDescription}">
</head>
<body>
<h1>${content.title}</h1>
<p>${content.body}</p>
</body>
</html>
`);
} catch (error) {
console.error('Error fetching homepage content:', error);
res.status(500).send('Internal Server Error');
}
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
```
The code above provides dynamic meta descriptions for SEO improvements by making an API call before rendering the page.
Feature | Node Fetch | Axios |
Installation | Lightweight | Lightweight |
Promise-based | Yes | Yes |
Browser compatibility | Primarily Node.js | Node.js and browsers |
Automatic JSON parsing | Manual parsing required | Automatic JSON parsing |
Interceptors | Not built in | Supports request/response interceptors |
Error handling | Basic, manual checks | Enhanced, rejects on non-2xx status |
Request cancellation | AbortController | Cancellation tokens |
File operations | Manual handling | Simplified file handling |
Choose Axios if you need built-in interceptors, automatic JSON parsing, and enhanced error handling. Choose Node Fetch if you prefer a lightweight library, more control, and consistency with the Fetch API.
Feature | Node Fetch | native-fetch-pkg |
Installation | Lightweight | Lightweight |
Promise-based | Yes | Yes |
Browser compatibility | Primarily Node.js | Primarily Node.js |
Automatic JSON parsing | Manual parsing required | Manual parsing required |
Interceptors | Not built in | Not built in |
Error handling | Basic, manual checks | Basic, manual checks |
Request cancellation | AbortController | AbortController |
Community/maintenance | Large, active | Smaller, less active |
Choose Node Fetch if you prefer a well-supported library. Choose native-fetch-pkg if you prefer a minimalistic approach.
Pros
Cons
```javascript
const fetch = require('node-fetch');
const fetchWithRetry = async (url, options = {}, retries = 3, backoff = 300) => {
try {
const response = await fetch(url, options);
if (!response.ok) {
if (response.status >= 400 && response.status < 500) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (retries > 0) {
console.warn(`Retrying... Attempts left: ${retries}. Error: ${error.message}`);
await new Promise(res => setTimeout(res, backoff));
return fetchWithRetry(url, options, retries - 1, backoff * 2);
} else {
console.error('Max retries reached. Error:', error);
throw error;
}
}
};
const getData = async () => {
try {
const data = await fetchWithRetry('https://api.example.com/data', {}, 3, 500);
console.log('Data retrieved successfully:', data);
} catch (error) {
console.error('Failed to fetch data after retries:', error);
}
};
getData();
```
This code provides an example of Fetch with retry logic using exponential backoff.
Integrating monitoring tools like Stackify Retrace provides insights into your application’s behavior and helps quickly resolve issues when using Node Fetch for HTTP requests.
Stackify Retrace is an application monitoring tool that tracks and optimizes applications. Integrating Stackify with Node Fetch helps you monitor HTTP requests in real time, identifying and addressing problems faster.
Node Fetch simplifies HTTP requests in Node.js by using the standard Fetch API, a promise-based interface, and streaming support. Although Node Fetch requires manual handling for tasks like JSON parsing and error management, its lightweight design provides a foundation for building scalable applications.
Start your free Retrace trial today to improve observability and enhance your application’s performance and reliability. Combining Stackify Retrace with Node Fetch unlocks insights, optimizes performance, and delivers better user experiences.
If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]