DEV Community

Cover image for Getting Started with JavaScript Fetch API
Vaibhav Mehta
Vaibhav Mehta

Posted on

Getting Started with JavaScript Fetch API

Prelude

Have you ever used XMLHttpRequest object in JavaScript to send a request to the backend to fetch or post some data? If not, then lucky you, as it was pretty chaotic and complicated.

Here's a quick example of what it takes to fetch a file from a given URL using XMLHttpRequest object vs $.ajax() in jQuery vs newly introduced native fetch API.


Fetching Data using XMLHttpRequest

var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function() {
  if (xhr.readyState == XMLHttpRequest.DONE) {
    console.log(xhr.responseText);
  }
}

xhr.open('GET', 'https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a42', true);
xhr.send(null);
Enter fullscreen mode Exit fullscreen mode

Looks tedious right? That's not it, the above is mostly a minimal example of how to send a request using XMLHttpRequest() object. Next, jQuery comes to the rescue by introducing $.ajax(), a simplified version of the XMLHttpRequest() as a cherry on top, introducing additional functionalities.


Fetching Data using $.get()

$.get(
  'https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a42',
  (res) => {
    console.log(res);
  }
);
Enter fullscreen mode Exit fullscreen mode

jQuery simplified fetching the data to a great extent, compared to the native XMLHttpRequest() object. Though it was easy, it came at some cost, as the jQuery lib weighed ~100kb (vague estimation) where even if you built the lib with ajax only module, it still weighed roughly ~50kb which is pretty high to do something as basic as fetching some JSON data.

Before we dive into using fetch() API, here's something important to take a note of:

The fetch specification differs from jQuery.ajax() in the following significant ways:

  1. The Promise returned from fetch() won't reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, as soon as the server responds with headers, the Promise will resolve normally (with the ok property of the response set to false if the response isn't in the range 200–299), and it will only reject on network failure or if anything prevented the request from completing. [1]

  2. Unless fetch() is called with the credentials option set to include, fetch() Quoting from MDN:

    • Won't send cookies in cross-origin requests.
    • Won't set any cookies sent back in cross-origin responses.

Introducing the fetch() API

fetch API is supported by most of the modern browsers today. It makes it easier for the devs to make asynchronous network requests as it's promise based, thus, avoids callback hell.

Here's a simple example of making a GET request using fetch API.

fetch('https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a42')
  .then((res) => res.json())
  .then((data) => console.log(data));
Enter fullscreen mode Exit fullscreen mode

You could also use async ... await instead of promises, like:

(async () => {
  const res = await fetch('https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a42');
  const data = await res.json();
  console.log(data);
})();
Enter fullscreen mode Exit fullscreen mode

In the above examples, fetch() takes one argument which is the path to the resource you wish to fetch. An important thing to note here, the response does not return the JSON response body but it instead a representation of the entire HTTP response where you could use .json() to fetch the actual response JSON data.

fetch also provides various options which you could use for the response object, like, text() which returns raw text, formData(), blob(), etc.


Error Handling

When I first tried fetch, I used .catch() assuming that my code would end up in the .catch() statement if the request was a non 200. To my surprise, .catch() never ran, even if the request failed with a response code of 4xx or 5xx. As mentioned previously in this post.

For eg, the following URL would throw a 404 error.

fetch('https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a4a')
  .then((res) => res.json())
  .then((data) => console.log(data))
  .catch((err) => console.log('Something went wrong'));
Enter fullscreen mode Exit fullscreen mode

Here, my code didn't print Something went wrong. Later, referring to the official documentation, it turns out that fetch doesn't throw an error if the server returns an error (4xx or 5xx).

The only time my code would end up in the catch statement is when there's no internet connection, or similar issues. Here's where response.ok comes to the rescue. Using response.ok would return true if the response status code is between 200-299 else false.

In the above example, using response.ok to check the request state would return false as the response code was 404.

(async () => {
  const res = await fetch('https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a42');
  if(!res.ok) {
    throw new Error(`'Request failed with status code: ${res.status}`);
  }

  const data = await res.json();
  console.log(data);
})();
Enter fullscreen mode Exit fullscreen mode

Attaching Request Headers & Payload

In the above examples, we tried to fetch these records using the default GET method.

But what if you wish to send a POST or a PUT request along with some Headers attached to it?

You could pass headers and attach a payload to your fetch request either by using Headers() object or you could simply pass these in an object as a second parameter to the fetch API like:

(async () => {
  const res = await fetch('https://api.jsonbin.io/v3/b/6360e54a65b57a31e6a94a42', 
  {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    headers: { // Request headers
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({"sample": "json"}) // Request payload
  });

  if(!res.ok) {
    throw new Error(`'Request failed with status code: ${res.status}`);
  }

  const data = await res.json();
  console.log(data);
})();
Enter fullscreen mode Exit fullscreen mode

fetch() vs. XHR

There are a few differences between the fetch API and XHR request. I didn't want to repeat or copy these since I myself got to know about these differences from a Stackoverflow answer.


Browser Support

fetch() API now has a decent Browser Support. Here's a quick Browser Support overview from MDN:

Browser Support for fetch() JavaScript

You could also use fetch in NodeJS using --experimental-fetch flag, or use the node-fetch package if needed.


Resources

Top comments (0)