Fetch API Explained: Handling Responses, Headers, Abort Signals, and Download Progress

Javascript can send a network requests to server and load new information whenever it is needed. There are multiple ways to send request to server. The fetch() method is a modern way to send a network request. It is promise based and integrated with modern web such as service workers and CORS.

The basic syntax is

let promise = await fetch(url , [options]);

url — the url on which you want to send request

options — optional parameters: method , headers , etc

The fetch method returs a promise that we use to get response. There are two stages to get a response. First stage is the promise resolve with an object of built in response class , as soon as server responds with headers. At this stage , we can check http status and headers but don’t have response body yet. The promise rejects the fetch was unable to make http request because of some network problem.

Second stage is to call additional method to get response body in any format that we want. Response provide multiple promise based methods to access the body in different formats.

  1. Response.text — read the response and return as text.
  2. Response.json — parse the response as JSON.
  3. Response.formData — return the response as FormData object
  4. Response.blob — return the response as Blob (binary data with type)
  5. Response.arrayBuffer — return the response as arrayBuffer(low level representation of binary data)

Note — We can choose only one format to get response body. If we already got the response with response.text() , then response.json() will not work, as the body content already processed.

Fetch Headers

Headers are the key-value pairs or map-like object that act as metadata attached to both request and response. Common Headers are

  1. Content-Type — Tell the server the format of the data in the request body. Ex — for json , its value is application/jsonand for formData , it is application/x-www-form-urlencoded or multipart/form-data
  2. Authorization — Used to send authentication credentials , typically tokens.
  3. Accept — Informs the server about the data format that client expects in the response.
  4. Cache-Control — Specifies caching directives for both requests and responses (e.g., no-cache, max-age=3600).
  5. If-Modified-Since — Makes the request conditional, only retrieving the resource if it has been modified after the specified date.
  6. User-Agent — Identifies the user agent (browser or application) making the request.
  7. Referer — Indicates the URL of the page that linked to the requested resource.
  8. Origin — Used in cross-origin requests to indicate the origin of the request.
  9. Content-Length — Specifies the size of the request body in bytes.

Fetch Body

The request body is the payload of the request. It is send by client to the server. We cannot send the body in get request. We can send request body as a string, ArrayBuffer, typedArray, FormData , File, Blob, DataView, URLSearchParams. Other objects are converted to strings using their toString() method.

FormData objects are used to capture HTML form and submit it using fetch or another network method.

We can either create new FormData(form) from an HTML form, or create an object without a form at all, and then add fields with methods:

  • formData.append(name, value)
  • formData.append(name, blob, fileName)
  • formData.set(name, value)
  • formData.set(name, blob, fileName)

Note — Just like response body , request bodies are streams, making the request read the streams .So ,if a request contains body , you can’t make it twice.

How to cancel the fetch Request?

As we know, fetch returns a promise and in javascript , there is no concept of aborting a promise. So, for this, we have a special built in object called AbortController. It can be used to abort other asynchronous task as well.

The AbortController Object is an extremely simple object.

  • It has a single method abort(),
  • And a single property signal that allows to set event listeners on it.
const controller = new AbortController();
let signal = controller.signal;
signal.addEventListener("abort" , ()=> alert("abort!"));
controller.abort();
alert(signal.aborted); // true

Using abortcontroller with fetch

const controller = new AbortController();
const id = setTimeout(()=>controller.abort() , 3000);
try{
let promise = fetch(url , {
signal: controller.signal
});
clearTimeout(id);
} catch(err){
if(err.name === "AbortError"){
alert("aborted");
} else{
throw err;
}
}

Note — AbortController is scalable. It allows to cancel the multiple request once. If we have other asynchronous task, different from fetches, then we can use a AbortController to stop those, together with fetches.

We can also use AbortSignal.timeout() to cancel the request.

let promise = fetch(url , {
signal: AbortSignal.timeout(5000),
})

Monitor the Progress of Fetch Request

Suppose we have to display a visual progress bar or percentage indicator for large file downloads (e.g., videos, audio, software updates, large datasets). How can we check how much data is downloaded ?

Solution —

The fetch method allows you to track download progress. To track download progress, we can use response.body property. Unlike response.json() , response.text() and other methods, response.body() which is a readable stream, gives full control over reading process, and we can check how much content is consumed till now.

Here’s the full working example that gets the response and logs the progress in console —

let promise = await fetch(url);
const reader = promise.body.getReader();
const totalLength = promise.headers.get("Content-length");
let receivedLength = 0;
let chunks = [];// array of received binary chunks (consist the body)
while(true){
const { done, value } = await reader.read();
if(done){
break;
}
chunks.push(value);
receivedLength += value.length;
console.log(`Percentage is {(receivedLength/totalLength)*100}`);
}

The result of await reader.read() call is an object with two properties:

  • donetrue when the reading is complete, otherwise false.
  • value – a typed array of bytes: Uint8Array.

We receive response chunks in the loop, until the loading finishes, that is: until done becomes true.

Note — Currently , there is no way to track upload progress using fetch api.

Conclusion

In this article, we explored how network requests work with the Fetch API — from understanding responses, headers, and body handling to canceling requests with AbortController and tracking download progress. With these techniques, you now have a solid foundation for building more robust and user-friendly web applications that efficiently manage network interactions.

Thanks for reading — and as always,

Happy coding! 🚀

Learn more Fetch API Explained: Handling Responses, Headers, Abort Signals, and Download Progress

Leave a Reply