JavaScript Fetch API

Introduction to Fetch API

The Fetch API provides a JavaScript interface for accessing and manipulating parts of the protocol, such as requests and responses. It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.


A Basic Fetch Request

A basic fetch request looks like this:

Try yourself
        
            
async function getLogs() {
  const response = await fetch("http://example.com/logs.json");
  const logs = await response.json();
  console.log(logs);
}

        
    

Supplying Request Options

The fetch() method can optionally accept a second parameter, an init object that allows you to control a number of different settings.

Try yourself
        
            
 //Example POST method implementation:
 async function postData(url = "
     ", data = {}) {
     //Default options are marked with *
     const response = await fetch(url, {
         method: "
         POST ", //*GET, POST, PUT, DELETE, etc.
         mode: "
         cors ", //no-cors, *cors, same-origin
         cache: "
         no - cache ", //*default, no-cache, reload, force-cache, only-if-cached
         credentials: "
         same - origin ", //include, *same-origin, omit
         headers: {
             "
             Content - Type ": "
             application / json ",
             //'Content-Type': 'application/x-www-form-urlencoded',
         },
         redirect: "
         follow ", //manual, *follow, error
         referrerPolicy: "
         no - referrer ", //no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
         body: JSON.stringify(data), //body data type must match "Content-Type" header
     });
     return response.json(); //parses JSON response into native JavaScript objects


        
    

Aborting a Fetch

To abort incomplete fetch() operations, use the AbortController and AbortSignal interfaces.

Try yourself
        
            
const controller = new AbortController();
const signal = controller.signal;
const url = "video.mp4";

const downloadBtn = document.querySelector("#download");
const abortBtn = document.querySelector("#abort");

downloadBtn.addEventListener("click", async () => {
  try {
    const response = await fetch(url, { signal });
    console.log("Download complete", response);
  } catch (error) {
    console.error(``Download error: ${error.message}``);
  }
});

abortBtn.addEventListener("click", () => {
  controller.abort();
  console.log("Download aborted");
});

        
    

Sending a Request with Credentials

To cause browsers to send a request with credentials included on both same-origin and cross-origin calls, add credentials: 'include' to the init object you pass to the fetch() method.

Try yourself
        
            
fetch("https://example.com", {
  credentials: "include",
});

        
    

Uploading JSON Data

Use fetch() to POST JSON-encoded data.

Try yourself
        
            
async function postJSON(data) {
  try {
    const response = await fetch("https://example.com/profile", {
      method: "POST", // or 'PUT'
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(data),
    });

    const result = await response.json();
    console.log("Success:", result);
  } catch (error) {
    console.error("Error:", error);
  }
}

const data = { username: "example" };
postJSON(data);

        
    

Uploading a File

Files can be uploaded using an HTML <input type='file' /> input element, FormData() and fetch().

Try yourself
        
            
async function upload(formData) {
  try {
    const response = await fetch("https://example.com/profile/avatar", {
      method: "PUT",
      body: formData,
    });
    const result = await response.json();
    console.log("Success:", result);
  } catch (error) {
    console.error("Error:", error);
  }
}

const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');

formData.append("username", "abc123");
formData.append("avatar", fileField.files[0]);

upload(formData);

        
    

Uploading Multiple Files

Files can be uploaded using an HTML <input type='file' multiple /> input element, FormData() and fetch().

Try yourself
        
            
async function uploadMultiple(formData) {
  try {
    const response = await fetch("https://example.com/posts", {
      method: "POST",
      body: formData,
    });
    const result = await response.json();
    console.log("Success:", result);
  } catch (error) {
    console.error("Error:", error);
  }
}

const photos = document.querySelector('input[type="file"][multiple]');
const formData = new FormData();

formData.append("title", "My Vegas Vacation");

for (const [i, photo] of Array.from(photos.files).entries()) {
  formData.append(`photos_${i}`, photo);
}

uploadMultiple(formData);

        
    

Processing a Text File Line by Line

The chunks that are read from a response are not broken neatly at line boundaries and are Uint8Arrays, not strings. If you want to fetch a text file and process it line by line, it is up to you to handle these complications.

Try yourself
        
            
async function* makeTextFileLineIterator(fileURL) {
    const utf8Decoder = new TextDecoder("utf-8");
    const response = await fetch(fileURL);
    const reader = response.body.getReader();
    let { value: chunk, done: readerDone } = await reader.read();
    chunk = chunk ? utf8Decoder.decode(chunk) : ";

    const newline = /\\r?\\n/gm;
    let startIndex = 0;
    let result;

    while (true) {
        const result = newline.exec(chunk);
        if (!result) {
            if (readerDone) break;
            const remainder = chunk.substr(startIndex);
            ({ value: chunk, done: readerDone } = await reader.read());
            chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : ");
            startIndex = newline.lastIndex = 0;
            continue;
        }
        yield chunk.substring(startIndex, result.index);
        startIndex = newline.lastIndex;
    }

    if (startIndex < chunk.length) {
        // Last line didn't end in a newline char
        yield chunk.substr(startIndex);
    }
}

async function run() {
  for await (const line of makeTextFileLineIterator(urlOfFile)) {
    processLine(line);
  }
}

run();

        
    

Checking Fetch Success

A fetch() promise will reject with a TypeError when a network error is encountered or CORS is misconfigured on the server-side, although this usually means permission issues or similar — a 404 does not constitute a network error, for example.

Try yourself
        
            
async function fetchImage() {
    try {
        const response = await fetch("flowers.jpg");
        if (!response.ok) {
            throw new Error("Network response was not OK");
        }
        const myBlob = await response.blob();
        myImage.src = URL.createObjectURL(myBlob);
    } catch (error) {
        console.error("There has been a problem with your fetch operation:", error);
    }
}

        
    

Supplying Your Own Request Object

Instead of passing a path to the resource you want to request into the fetch() call, you can create a request object using the Request() constructor, and pass that in as a fetch() method argument.

Try yourself
        
            
async function fetchImage(request) {
    try {
        const response = await fetch(request);
        if (!response.ok) {
            throw new Error("Network response was not OK");
        }
        const myBlob = await response.blob();
        myImage.src = URL.createObjectURL(myBlob);
    } catch (error) {
        console.error("Error:", error);
    }
}

const myHeaders = new Headers();

const myRequest = new Request("flowers.jpg", {
    method: "GET",
    headers: myHeaders,
    mode: "cors",
    cache: "default",
});

fetchImage(myRequest);

        
    

Headers

The Headers interface allows you to create your own headers object via the Headers() constructor. A headers object is a simple multi-map of names to values.

Try yourself
        
            
const content = "Hello World";
const myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");

        
    

Differences from jQuery.ajax()

The fetch specification differs from jQuery.ajax() in several significant ways. Here are some key differences:


Summary

The Fetch API is a powerful tool for making HTTP requests in JavaScript. It provides a cleaner and more flexible syntax compared to the older XMLHttpRequest. By understanding how to use Fetch, you can efficiently communicate with servers and handle responses.