The Fetch API provides a modern alternative to XMLHttpRequest for making network requests in JavaScript. With the release of Node.js v17.5, Fetch API is now available for use in server-side JavaScript as well.
In this in-depth guide, we‘ll cover how to fully leverage Fetch API for making HTTP requests in Node.js.
A Brief History of Fetch API
The Fetch API specification was first published in 2014 to provide a more powerful and flexible replacement for XMLHttpRequest (XHR). It uses Promises and other modern JavaScript features which enable cleaner asynchronous code compared to callbacks.
Browser support for Fetch API landed in Chrome and Firefox later in 2014. By 2017, Fetch had >90% browser support and was ready for mainstream use.
Meanwhile on the server side, node-fetch was released as a polyfill module in 2016. It allowed Node.js developers to use a Fetch API-like interface for HTTP requests.
Finally in Feb 2024, experimental support for Fetch API landed in Node.js v17.5. This eliminated the need for a separate polyfill module like node-fetch for server-side requests.
Fetch API adoption continues to grow thanks to its flexibility and ease of use for modern web development. Next, let‘s see it in action!
Making Requests with Fetch API
The syntax for making a request with Fetch API is simple:
fetch(url, options)
This returns a Promise that resolves with a Response object containing the request result.
To make a basic GET request:
fetch(‘https://api.example.com/data‘)
.then(response => {
// handle response
})
Fetch API defaults to GET requests if no method is specified.
For other HTTP methods, pass the method
in options:
fetch(url, {
method: ‘POST‘
})
Supported HTTP request methods in Fetch API are:
- GET
- POST
- PUT
- DELETE
- HEAD
- OPTIONS
Next let‘s look at sending request headers, data, and other options with Fetch.
Fetch API Options
The second optional argument for fetch()
is an options object that allows you to customize the request:
const options = {
method: ‘POST‘,
headers: {
‘Content-Type‘: ‘application/json‘
},
body: JSON.stringify(data)
}
fetch(url, options)
Here are some of the commonly used options:
Option | Description |
---|---|
method | HTTP request method e.g. GET, POST |
headers | Object of request headers to set |
body | Request body (string, FormData, BufferSource, etc) |
redirect | Redirect mode e.g. follow, error |
cache | Cache mode e.g. default, no-cache |
This allows full control over the HTTP request from within Fetch.
Request Body
For POST, PATCH, and PUT requests, you will likely need to send data in the request body.
The body
option accepts different types including:
- String
- FormData
- JSON object – convert to string with
JSON.stringify()
- Blob / BufferSource
- ArrayBuffer
For example, to send JSON:
const body = {
name: ‘John‘,
age: 30
};
fetch(url, {
method: ‘POST‘,
headers: {
‘Content-Type‘: ‘application/json‘
},
body: JSON.stringify(body)
})
Form data can be sent as:
const formData = new FormData();
formData.append(‘name‘, ‘John‘);
fetch(url, {
method: ‘POST‘,
body: formData
});
This makes it straightforward to send requests with any kind of structured data.
Handling Fetch Responses
The Promise returned by the Fetch call resolves to a Response object containing the response details:
fetch(url).then(response => {
// response.status
// response.ok
// response.headers
})
The Response object has properties like status
, ok
, and headers
which contain metadata about the response.
To extract the actual response body content, these methods are available:
- .text() – Get response as text string
- .json() – Parse JSON response
- .blob() – Get Blob object
- .arrayBuffer() – Get ArrayBuffer
For example:
fetch(url)
.then(response => response.json())
.then(data => {
// use JSON data
})
So Fetch API handles parsing the response for you based on the Content-Type header.
Response Status Codes
HTTP response status codes like 200, 404, 500 are available on the Response status
property.
To check if a request succeeded:
fetch(url).then(response => {
if (response.ok) {
// request succeeded
} else {
// request failed
}
})
The .ok
property is a shorthand for status in the 200-range.
Streams
Fetch API also supports streams which allow processing the response incrementally as chunks arrive:
const response = fetch(url);
const reader = response.body.getReader();
reader.read().then( ({done, value}) => {
// handle chunk
})
This avoids buffering the entire response in memory for large responses.
Handling Errors
Since Fetch uses Promises, errors can be caught using .catch()
:
fetch(url)
.then(/* ... */)
.catch(error => {
console.error(error)
});
Or with async/await:
try {
const response = await fetch(url);
} catch (error) {
console.error(error);
}
This catches any network errors or HTTP status errors.
To retry on failure, use recursion or a retry loop:
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms))
const fetchWithRetry = async (url, retries=3, delayMs=3000) => {
for (let retry=1; retry<=retries; retry++) {
try {
return await fetch(url);
} catch(error) {
if (retry < retries) {
await delay(delayMs);
continue;
}
throw error;
}
}
}
More robust error handling ensures the request succeeds even with faults.
Comparison of Fetch API, Axios, and Node HTTP Module
Fetch API provides a powerful and convenient way to make HTTP calls in JavaScript. But how does it compare to alternatives like Axios and native Node.js modules?
Features
Feature | Fetch API | Axios | Node HTTP |
---|---|---|---|
Promise-based | ✅ | ✅ | |
Interceptors | ✅ | ||
Streams | ✅ | ✅ | |
Timeout handling | ✅ | ✅ | |
Cancellation | ✅ | ✅ | |
Browser support | ✅ |
Fetch – Fully promise-based with wide browser support. Streams but no interceptors or timeout handling.
Axios – Promise-based with advanced features like interceptors, cancellation, and timeout handling. Browser usage requires polyfill.
Node HTTP – Core HTTP module in Node.js with streams and timeouts. Callback-based.
Performance
Fetch API performance is comparable to Axios for basic usage according to benchmarks.
However, Axios may be faster when using some advanced features due to its optimizations. Node HTTP can be the fastest when pipelining requests.
Use Cases
Fetch – Great for browser HTTP requests and integration with frontend. Also easy to use on the server.
Axios – Full-featured for robust HTTP requests from Node.js. Excellent for API clients.
Node HTTP – When performance and low-level control is critical. Can utilize keep-alive connections.
So in summary, Fetch API hits a nice sweet spot between simplicity and features.
Conclusion
I hope this guide has provided a comprehensive overview of making HTTP requests with Fetch API in Node.js. Some key takeaways:
- Fetch provides an easy and modern API for network requests using Promises
- It supports all common HTTP methods like GET, POST, PUT, DELETE
- Request headers, body, timeouts, redirects can be configured via the options
- Responses are streamed with helper methods like .text(), .json() for parsing
- Fetch is similar to Axios but without some advanced features like interceptors
- For basic HTTP calls from Node.js or browser, Fetch API is an excellent choice
Fetch API usage will continue grow, especially with support now in Node.js itself. The simple yet powerful API encourages cleaner async code compared to callbacks or XHR.
I hope you found this guide helpful! Let me know if you have any other Fetch API questions.