How to get response body when using fetch() in JavaScript

Apr 28, 2023#javascript#how-to

FetchAPI is designed to be easy to use and supports many different data formats including JSON, XML, and binary data. It provides a simple promised-based syntax for making HTTP requests and can be used in both the browser and Node.js environments.

When you use the fetch() method to make a request to a server, you will get back a promise that resolves to a Response object. The Response object represents the entire HTTP response, including the status, headers, and body. However, the body is not directly accessible as a string or an object, but rather as a stream of data that can only be read once.

To handle the response body, you need to use one of the methods of the Response object that returns another promise that resolves to the parsed data. These methods are:

  • .json(): Returns a Promise that resolves with the parsed JSON.
  • .text(): Returns a promise that resolves with a String.
  • .blob(): Returns a promise that resolves with a Blob, which represents a file-like object of immutable, raw data.
  • .arrayBuffer(): Returns a promise that resolves with an ArrayBuffer, which represents a generic, fixed-length binary data buffer.
  • .formData(): Returns a promise that resolves with a FormData, which is a key-value pair data structure used to submit form data.

Using .json()

Despite the method being named .json(), the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object. This object could be anything that can be represented by JSON — an object, an array, a string, a number, etc.

Use this method when you want to get the response body as a JavaScript object parsed from JSON text. This is useful for working with data that follows the JSON format, such as most APIs. For example, you can use this method to get the user information from a GitHub API or the weather data from a weather API.

Here’s an example of making a request to the Reddit API and display the titles of the top posts on the front page using the .json() method:

async function getRedditPosts() {
  try {
    const response = await fetch('https://www.reddit.com/r/all/top.json?limit=10');
    const data = await response.json();
    const posts = data.data.children.map(child => child.data);
    console.log(posts.map(post => post.title));
  } catch (error) {
    console.error(error);
  }
}

// Using Promise syntax:
function getRedditPosts() {
  fetch('https://www.reddit.com/r/all/top.json?limit=10')
    .then(response => response.json())
    .then(data => {
      const posts = data.data.children.map(child => child.data);
      console.log(posts.map(post => post.title));
    })
    .catch(error => console.error(error));
}

Using .text()

Use this method when you want to get the response body as a plain text string, regardless of the content type. This is useful for debugging purposes or when you need to process the text yourself. For example, you can use this method to get the HTML source code of a web page or the XML data of an RSS feed.

Here’s an example of making a request to the GitHub API and displaying the contents of a file using the .text() method.

async function displayFileContentsAsync() {
  try {
    const response = await fetch('https://api.github.com/repos/github/gitignore/contents/Node.gitignore');
    const text = await response.text();
    console.log(text);
  } catch (error) {
    console.error(error);
  }
}

// Using Promise syntax:
function displayFileContentsPromise() {
  fetch('https://api.github.com/repos/github/gitignore/contents/Node.gitignore')
    .then(response => response.text())
    .then(text => console.log(text))
    .catch(error => console.error(error));
}

Using .blob()

Use this method when you want to get the response body as a Blob object containing binary data. This is useful for working with data that is not text-based, such as images, videos, audio, or PDF files. For example, you can use this method to get an image from an image API or a PDF file from a document API.

Here’s an example of making a request to an image file on a server using the .blob() method:

async function displayImageAsync() {
  try {
    const response = await fetch('https://www.example.com/image.jpg');
    const blob = await response.blob();
    const url = URL.createObjectURL(blob);
    const img = document.createElement('img');
    img.src = url;
    document.body.appendChild(img);
  } catch (error) {
    console.error(error);
  }
}

// Using Promise syntax:
function displayImagePromise() {
  fetch('https://www.example.com/image.jpg')
    .then(response => response.blob())
    .then(blob => {
      const url = URL.createObjectURL(blob);
      const img = document.createElement('img');
      img.src = url;
      document.body.appendChild(img);
    })
    .catch(error => console.error(error));
}

Using .arrayBuffer()

Use this method when you want to get the response body as an ArrayBuffer object containing raw bytes. This is useful for working with data that requires low-level manipulation, such as encryption, compression, or decoding. For example, you can use this method to get a ZIP file from a file API or a WAV file from an audio API.

Here’s an example of making a request to an audio file on a server using the .arrayBuffer() method:

async function playAudioAsync() {
  try {
    const response = await fetch('https://www.example.com/audio.mp3');
    const arrayBuffer = await response.arrayBuffer();
    const audioBuffer = await new AudioContext().decodeAudioData(arrayBuffer);
    const source = new AudioBufferSourceNode(new AudioContext(), { buffer: audioBuffer });
    source.connect(new AudioContext().destination);
    source.start(0);
  } catch (error) {
    console.error(error);
  }
}

// Using Promise syntax:
function playAudioPromise() {
  fetch('https://www.example.com/audio.mp3')
    .then(response => response.arrayBuffer())
    .then(arrayBuffer => new AudioContext().decodeAudioData(arrayBuffer))
    .then(audioBuffer => {
      const source = new AudioBufferSourceNode(new AudioContext(), { buffer: audioBuffer });
      source.connect(new AudioContext().destination);
      source.start(0);
    })
    .catch(error => console.error(error));
}

Using .formData()

Use this method when you want to get the response body as a FormData object containing form data. This is useful for working with data that is submitted using HTML forms, such as multipart/form-data or application/x-www-form-urlencoded. For example, you can use this method to get the user input from a contact form or a file upload form.

This method is rarely used because most APIs do not return form data as a response, but rather JSON or XML data. Also, FormData objects are not easy to inspect or manipulate, as they do not have a built-in way to iterate over their entries or convert them to other formats.

However it is particularly useful in the context of service workers due to their ability to intercept network requests and manipulate their data.

Service workers are scripts that run in the background of a web application and can intercept and handle network requests. By using the .formData() method, you can intercept a form submission request, modify the form data, and then send the modified form data to the server. This can be useful for a variety of purposes, such as logging form data, adding extra fields to the form data, or filtering sensitive data.

Here’s an example of a service worker intercepting a form submission request and modifying the form data using the .formData() method:

self.addEventListener('fetch', event => {
  // Intercept form submission requests
  if (event.request.method === 'POST' && event.request.headers.get('Content-Type') === 'application/x-www-form-urlencoded') {
    event.respondWith(handleFormSubmission(event.request));
  }
});

async function handleFormSubmission(request) {
  // Parse the form data from the request body
  const formData = await request.formData();

  // Modify the form data
  formData.append('extra-field', 'extra-value');

  // Create a new request with the modified form data
  const newRequest = new Request(request.url, {
    method: request.method,
    headers: request.headers,
    body: new URLSearchParams(formData)
  });

  // Make the modified request to the server
  return fetch(newRequest);
}