The Fetch API is one of the most used ways to make HTTP requests in JavaScript. It allows you to send and receive data from servers simply and efficiently. While it has been used in browser-based applications, recent updates to Node.js have introduced experimental support for the Fetch API so you can write server-side code without relying on third-party libraries.

This post will show you how to use the Fetch API in Node.js to make HTTP requests. Whether you need to make GET or POST requests, handle headers, or compare Fetch API with Axios, this post will help you get started. Let’s get into it!

Table Of Contents

  1. Why Use Fetch API for HTTP Requests?
  2. Setting Up Fetch API in Node.js
  3. Making GET Requests With Fetch API
  4. Handling Response Headers in Fetch API
  5. Sending POST Requests With Fetch API
  6. Error Handling in Fetch API
  7. Fetch API vs Axios: Key Differences
  8. Final Thoughts
  9. Frequently Asked Questions

Why Use Fetch API for HTTP Requests?

The Fetch API is a modern and flexible way to make HTTP requests in JavaScript. It simplifies the process of talking to APIs and servers using promises and makes your code cleaner and more maintainable.

Image shows reasons to use Fetch API for HTTP Requests

Here are some reasons why developers love the Fetch API:

  1. Built-in Support in Modern JavaScript
    Fetch API is supported in all browsers, and since Node.js 17.5, it’s also supported in server-side JavaScript. No need for third-party libraries like Axios or node-fetch.

  2. Promise-Based Approach
    Unlike older methods like XMLHttpRequest, Fetch API uses promises so you can avoid callback hell and write more readable asynchronous code.

  3. Flexible and Customizable
    Fetch API supports all common HTTP methods (GET, POST, PUT, DELETE) and allows you to add custom headers, handle JSON data easily, and manage different types of requests and responses.

  4. Lightweight Solution
    Since the Fetch API is built into modern JavaScript environments, you don’t need to install additional libraries, reducing your project’s dependencies and improving efficiency.

Setting Up Fetch API in Node.js

Before you can use the Fetch API in Node.js, you need to set up your environment correctly. Fetch API is available natively in Node.js 17.5 and above but is still experimental in some versions. Let’s go through the setup process.

Step 1: Check Your Node.js Version

To use Fetch API without installing extra libraries, you need Node.js 17.5 or above. Run the following command in your terminal to check your Node.js version:

1
node -v

If your version is below 17.5, download the latest from the official website.

Step 2: Enable Experimental Fetch API (Optional)

If you are using 17.5 or above but still find Fetch API experimental, you may need to enable it. Use --experimental-fetch when running your code:

1
node --experimental-fetch your_code.js

Step 3: Create a Node.js Project

If you’re starting from scratch, create a new Node.js project. Use the following commands to initialize your project and create a file for your code:

1
2
3
4
mkdir fetch-api-demo
cd fetch-api-demo
npm init -y
touch app.js

Step 4: Use Fetch API

You can now write Fetch API code directly in your app.js file. For example, a basic GET request looks like this:

1
2
3
4
5
6
7
8
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error('Error:', error);
});

Using a Third-Party Library (Optional)

If you’re working with an older version of Node.js or prefer not to upgrade, you can still use the Fetch API by installing the node-fetch library. Install it with:

1
npm install node-fetch

Then, import and use it in your code like this:

1
2
3
4
5
6
7
8
9
10
const fetch = require('node-fetch');

fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error('Error:', error);
});

Setting up Fetch API in Node.js is easy. Once done, you can start making HTTP requests. In the next section, we’ll see how to use Fetch API for GET requests.

Making GET Requests With Fetch API

GET requests are the most common type of HTTP request used to fetch data from a server. With Fetch API in Node.js, making GET requests is easy. Let’s see how to make GET requests and handle responses.

Basic GET Request Example

The Fetch API allows you to fetch data using the fetch() function, which takes the URL of the resource as its first parameter. Here’s an example of making a basic GET request:

1
2
3
4
5
6
7
8
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json()) // Parse the JSON response
.then((data) => {
console.log('Post:', data);
})
.catch((error) => {
console.error('Error:', error);
});

Explanation:

  • fetch() sends an HTTP GET request to the URL.
  • response.json() extracts the JSON data from the response.
  • then() handles the response data.
  • catch() catches any errors.

Using Async-Await for GET Requests

Async-await makes the code cleaner. Here’s the same GET request using async-await:

1
2
3
4
5
6
7
8
9
(async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const data = await response.json();
console.log('Post:', data);
} catch (error) {
console.error('Error:', error);
}
})();

Key Benefits of Using Async-Await:

  • It simplifies promise handling by avoiding nested .then() calls.
  • It’s easier to read, especially for complex logic.

Fetching Multiple Resources

You can also fetch multiple resources at once. Here’s an example:

1
2
3
4
5
6
7
8
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => {
console.log('Posts:', data);
})
.catch((error) => {
console.error('Error:', error);
});

This code retrieves a list of posts from the API and logs them to the console.

Adding Query Parameters

To include query parameters in your GET request, append them to the URL like this:

1
2
3
4
5
6
7
8
9
const userId = 1;
fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
.then((response) => response.json())
.then((data) => {
console.log('User Posts:', data);
})
.catch((error) => {
console.error('Error:', error);
});

Handling Responses

The Fetch API provides flexibility to handle different response types such as plain text, JSON, or binary. Here’s how you can handle a plain text response:

1
2
3
4
5
6
7
8
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.text())
.then((data) => {
console.log('Plain Text Response:', data);
})
.catch((error) => {
console.error('Error:', error);
});

GET requests are the bread and butter of any web API. With Fetch API, you can do them and keep your code clean and readable. In the next section, we’ll look at handling response headers in Fetch API.

Handling Response Headers in Fetch API

Response headers provide important metadata about an HTTP response, such as content type, server details, or caching instructions. With Fetch API, you can access and work with these headers easily.

Accessing Response Headers

The Response object returned by the fetch() function has a headers property. This property is a Headers object, which allows you to read and modify response headers. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => {
// Loop through headers
for (let [key, value] of response.headers) {
console.log(`${key}: ${value}`);
}
return response.json();
})
.then((data) => {
console.log('Post:', data);
})
.catch((error) => {
console.error('Error:', error);
});

What’s Happening Here:

  • response.headers is an object with all the headers returned by the server.
  • for…of loop iterates through each header and prints the key-value pairs.

Commonly Used Headers

Some of the most common headers are:

  • Content-Type: The media type of the resource (e.g. application/json)
  • Cache-Control: Specifies caching behavior.
  • Authorization: Contains authentication credentials.

You can access specific headers using the get() method:

1
2
3
4
5
6
7
8
9
10
11
12
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => {
const contentType = response.headers.get('content-type');
console.log('Content-Type:', contentType);
return response.json();
})
.then((data) => {
console.log('Post:', data);
})
.catch((error) => {
console.error('Error:', error);
});

CORS and Restricted Headers

When using Fetch API in a browser, Cross-Origin Resource Sharing (CORS) rules may restrict which headers can be accessed. Only the following headers are exposed by default:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

In Node.js, none of these apply so you have full access to all headers.

Practical Use Case: Checking Response Status

You can use headers to check the status of the response before processing the body.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => {
if (response.ok) {
console.log('Response is OK');
} else {
console.log('Response Error:', response.status);
}
return response.json();
})
.then((data) => {
console.log('Post:', data);
})
.catch((error) => {
console.error('Error:', error);
});

This ensures you only process valid responses, making your code more robust.

By understanding and using response headers, you can manage metadata, handle errors, and optimize your API requests. In the next section, we’ll look at how to send POST requests with Fetch API.

Sending POST Requests With Fetch API

Fetch API makes it easy to send HTTP POST requests to APIs. A POST request is used when you want to send data to a server, e.g., submitting form data or creating a new record in a database.

Sending a Basic POST Request

To send a POST request, you need to include the method property in the fetch() options object. Additionally, the body property is used to specify the data you want to send. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const url = 'https://jsonplaceholder.typicode.com/posts';
const data = {
title: 'New Post',
body: 'This is the content of the post.',
userId: 1,
};

fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // Convert data to JSON string
})
.then((response) => response.json())
.then((data) => {
console.log('Response:', data);
})
.catch((error) => {
console.error('Error:', error);
});

What’s Happening Here:

  1. URL: The endpoint for the POST request.
  2. Method: Specifies the HTTP method (POST).
  3. Headers: Defines Content-Type to tell the server that the data is JSON.
  4. Body: Contains the JSON-encoded data to send.

Why Use JSON.stringify?

When sending data with Fetch API, it must be a string. That’s where JSON.stringify() comes in—it turns your JavaScript object into a JSON string the server can understand.

Handling Server Responses

After sending a POST request, you typically receive a response from the server. The response might include the status of the request and any new data created on the server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => {
if (response.ok) {
console.log('POST successful');
} else {
console.log('Error:', response.status);
}
return response.json();
})
.then((data) => {
console.log('Created Resource:', data);
})
.catch((error) => {
console.error('Error:', error);
});

Real-World Use Case

Let’s say you’re building a user registration form. Here’s how you can send the form data using a POST request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const user = {
name: 'John Doe',
email: '[email protected]',
password: 'securepassword',
};

fetch('https://example.com/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(user),
})
.then((response) => response.json())
.then((data) => {
console.log('User registered:', data);
})
.catch((error) => {
console.error('Error:', error);
});

Using the Fetch API for POST requests allows you to send data to servers. Next, we’ll cover error handling so your requests are robust.

Error Handling in Fetch API

Error handling is a big part of making HTTP requests with the Fetch API. It ensures your app handles network issues, invalid responses, or unexpected errors.

Why Is Error Handling Important?

When you make HTTP requests, many things can go wrong:

  • The server is down.
  • The URL is wrong.
  • The response is not what we expected.
  • The network will interrupt the request.

If you don’t handle errors, your app will fail or crash and the user will have a bad time.

Handling Errors With then and catch

The Fetch API returns a Promise. You can use the .catch() method to handle errors during the request.

Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
fetch('https://invalid-url.example.com')
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then((data) => {
console.log('Data:', data);
})
.catch((error) => {
console.error('Error during fetch:', error);
});

Key Points:

  • if (!response.ok) checks if the HTTP response status is in the 200–299 range. If not, it throws an error.
  • .catch() catches both network errors and errors thrown in the .then() chain.

Using Try-Catch With Async-Await

For cleaner code, you can use async and await with a try-catch block to handle errors.

Here’s the same example:

1
2
3
4
5
6
7
8
9
10
11
12
(async () => {
try {
const response = await fetch('https://invalid-url.example.com');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log('Data:', data);
} catch (error) {
console.error('Error during fetch:', error);
}
})();

Advantages of Try-Catch:

  • Easier to read and understand, especially for complex logic.
  • Groups error-handling code in one place.

Handling Timeouts

By default, the Fetch API doesn’t support request timeouts. However, you can create a custom timeout by using Promise.race().

Here’s how to implement it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fetchWithTimeout = (url, options, timeout = 5000) => {
return Promise.race([
fetch(url, options),
new Promise((_, reject) => setTimeout(() => reject(new Error('Request timed out')), timeout)),
]);
};

(async () => {
try {
const response = await fetchWithTimeout('https://example.com/data', {}, 3000);
const data = await response.json();
console.log('Data:', data);
} catch (error) {
console.error('Error:', error.message);
}
})();

What’s Happening Here:

  • Promise.race() runs two promises: one for the fetch request and one for the timeout.
  • If the fetch request takes longer than the timeout (3 seconds in this example), the timeout promise rejects the operation.

Common Error Scenarios to Watch For

  1. Invalid URLs: Ensure your API endpoints are correct. 2.** Network Issues**: Handle cases where the network is unavailable.
  2. Non-JSON Responses: If the server sends non-JSON data, the response.json() method will throw an error.
  3. CORS Issues: Make sure the server allows cross-origin requests if you’re running in a browser.

Logging Errors for Debugging

When an error occurs, logging it can help with debugging:

1
2
3
4
5
6
fetch('https://example.com/api')
.then((response) => response.json())
.catch((error) => {
console.error('Fetch failed:', error);
// Log to an error monitoring service like Sentry or Rollbar
});

Error handling will make your app more stable and reliable. In the next section, we’ll compare Fetch with Axios to help you decide which one to use.

Fetch API vs Axios: Key Differences

When working with HTTP requests in Node.js or the browser, the Fetch API and Axios are two options. Both are great but different. Let’s compare them based on key points to help you choose.

Image shows the Key Differences between Fetch API and Axios.

Which One Should You Use?

Both Fetch API and Axios have their uses, but it depends on your project:

  • Use Fetch API if you want a native, no external dependencies solution, and your project targets modern browsers or Node.js (with experimental support).
  • Use Axios if you need more features like interceptors, easier error handling, built-in timeouts, or request cancellation. Axios is also good for older browser support.

Final Thoughts

In this blog, we covered how to make HTTP requests in Node.js with the Fetch API. We looked at setting up Fetch, making GET and POST requests, handling response headers, and comparing Fetch with Axios.

The Fetch API is a simple, modern way to make HTTP requests in Node.js and browsers. It’s lightweight and works in most cases. But if you need interceptors or built-in timeouts, then Axios might be a better choice.

In summary, the Fetch API is good for most cases, and it is an easy and efficient way to handle network requests in Node.js.

Frequently Asked Questions

Q. What is the difference between Fetch API and Axios?

Fetch API and Axios are both ways to make HTTP requests in JavaScript, but there are key differences. Fetch is a native browser feature and comes with Node.js experimental support, Axios is a third-party library. Axios simplifies things like automatic JSON parsing and request/response interceptors, which Fetch doesn’t offer out of the box. Fetch, on the other hand, is simpler and doesn’t require extra dependencies.

Q. How do I handle errors with Fetch API in Node.js?

Error handling in Fetch API is simple. Since Fetch returns a promise, you can use .catch() to catch errors or use try...catch with async/await. For instance, using async/await, you can handle errors as follows:

1
2
3
4
5
6
7
try {
const response = await fetch(url);
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}

This ensures that any issues like network failures or invalid URLs are properly handled.

Q. Can I use Fetch API for POST requests in Node.js?

Yes, the Fetch API works great for making POST requests. You simply need to specify the method as POST and include a body (usually JSON). Here’s an example:

1
2
3
4
5
6
7
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' }),
});
const data = await response.json();
console.log(data);

This sends data to the server and handles the response as JSON.