Learn JavaScript Logo

Learn JavaScript

Fetch API JavaScript deep dive

fetch() on MDN

The Fetch API was launched back in 2015 and is now supported on more than 97% of browsers worldwide. It allows us to send a request to a server and receive a response.

The code snippets below are taken from LearnJavaScript.online.

Pre-requisite topics to learn fetch

To learn how the Fetch API works, you must be comfortable with the following JavaScript topics:

Basic syntax

The fetch(url) method takes one mandatory argument, the URL of the resource you want to fetch. It returns a promise that resolves to the Response to that request.

Since we generally want to work with JSON, we call the .json() method on the response, which also returns a promise.

Basic use case

Here's an example of how to use the Fetch API to make a GET request:


fetch("https://jsonplaceholder.typicode.com/todos/1")
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error(error));

The Fetch API is asynchronous. The fetch() method returns a promise, which is why we see the console.log calls in a different order than the code:


console.log("A"); 
fetch('https://jsonplaceholder.typicode.com/todos/1')
    .then(response => response.json())
    .then(data => console.log("B"));
console.log("C");

The fetch() function always returns a promise, which is why we call the .then() on its result.

Moreover, the response.json() also returns a promise, which is why we have another .then() call to resolve the second promise.

Async/await

Since fetch() and .json() return promises, you can await their result:


const init = async () => {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error(error);
    }
}
init();

Making a POST request

You can make a POST request by specifying the second argument as follows:


fetch('https://jsonplaceholder.typicode.com/todos', {
    method: "POST",
    body: JSON.stringify({
        data: "to",
        send: "here",
    }),
})
    .then(response => response.json())
    .then(data => console.log(data));

You can replace POST with other methods such as PUT or DELETE. By default, its value is GET.

Specifying headers

You can specify additional headers as follows:


fetch('https://jsonplaceholder.typicode.com/todos/1', {
    method: "GET",
    headers: {
        "Authorization": "Bearer token-here",
        "Content-Type": "application/json",
        "Accept": "application/json",
    }
})
    .then(response => response.json())
    .then(data => console.log(data));

Checking response status

The fetch API won't reject if a response code is different than 200. From the API's perspective, the fetch request was completed successfully.

You can throw, if you want, or implement a custom behavior if the response code is not in the 200 range (200-299):


fetch('https://jsonplaceholder.typicode.com/todos/1')
    .then(response => {
        if (response.ok) {
            // do something
        }
        return response.json();
    })
    .then(data => console.log(data));

The response.ok property is a boolean that describes whether the request was successful or not. So, if the response status was in the 2xx range, response.ok would be true. This can be used as a starting point to handle HTTP errors. Moreover, response.status can be used to get the specific HTTP status code.

Handling (network) errors

To handle network errors or errors in your code, such as calling response.json() on a response that's not valid JSON, you must add a .catch handler:


fetch('https://jsonplaceholder.typicode.com/todos/1')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => {
        console.error("There was an error", error);
    });

Canceling a fetch request

You can cancel a fetch request by using an AbortController:


const controller = new AbortController();
const signal = controller.signal;

fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => {
        if (error.name === 'AbortError') {
            console.log('Fetch was aborted');
        } else {
            console.error('There was an error', error);
        }
    });

// to cancel the request
controller.abort();

Fetching and parsing an XML document

You can fetch an XML document. Instead of using the response.json() method, you want to treat it as text and call the response.text() method instead.

Once you have the text response, you can use the DOMParser to parse the XML document:


fetch("https://learnjavascript.online/assets/topics/users.xml")
    .then(response => response.text())
    .then(data => {
        const parser = new DOMParser();
        const xml = parser.parseFromString(data, "application/xml");
        const firstUser = xml.querySelectorAll("user")[0];
        const userName = firstUser.querySelector("name").textContent;
        console.log(userName); // "Sam"
});

CORS errors

If you're trying to fetch data from a different domain, you might run into a CORS error. This is a security feature that prevents a website from making requests to a different domain.

Here's what the error looks like:

Access to fetch at 'X' from origin 'Y' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

If you own the other domain, you can fix this by enabling CORS on the server from which you're trying to fetch data. Here's an example of the headers. You must update the values to match your use case:

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

Conclusion

Working with the fetch API should be relatively easy if you're comfortable with promises. You can achieve many common use cases, such as fetching JSON, sending data, and handling errors.

Are you a student of LearnJavaScript.online? Review the Fetch chapters.

What do you think of this page? Give your feedback here.

Learn JavaScript LogoPowered by Learn JavaScript