Modern JavaScript API Consumption:
Mastering Fetch and HTTP Requests

Published on: April 14, 2025

JavaScript has revolutionized web development with its ability to handle asynchronous operations seamlessly. Among its many tools, the Fetch API stands out as a powerful interface for making HTTP requests. This blog explores how to master the Fetch API, covering its functionality, error handling, and practical use cases.

Basic components of Fetch API

The Fetch API provides a simple and elegant way to make network requests. The basic syntax is as follows:

javascript
1fetch(
2	// url
3	'https://jsonplaceholder.typicode.com/posts/1',
4	// options
5	{
6		method: 'GET',
7		headers: {
8			'Content-Type': 'application/json',
9		},
10		params: {
11			title: 'foo',
12			body: 'bar',
13		},
14	}
15)
16	.then(response => response.json())
17	.then(data => console.log(data))
18	.catch(error => console.error('Error fetching data:', error));
  1. url, The URL to which the request is sent.
  2. options.method, The HTTP method to use for the request.
  3. options.headers, Specifies the headers to include in the request. This is useful for setting content types or authentication tokens.
  4. options.params, This example makes a GET request to https://api.example.com/data?title=foo&body=bar.
  5. options.body, The body of the request, typically used for POST or PUT requests (not relevant for GET).
  6. Response Parsing, The response from the server can be parsed as JSON, text, or other formats using the appropriate methods. For example, to parse a JSON response, you can use response.json().

Using Async/Await with Fetch

javascript
1const fetchData = async () => {
2  // more readable, avoids callback hell
3	const response = await fetch(
4		'https://jsonplaceholder.typicode.com/posts/1',
5		{
6			method: 'GET',
7			headers: {
8				'Content-Type': 'application/json',
9			},
10			params: {
11				title: 'foo',
12				body: 'bar',
13			},
14		}
15	);
16	const data = await response.json();
17	return data;
18};

Error Handling

When using the Fetch API, it is essential to handle errors gracefully. The catch block is used to catch any errors that occur during the request. Additionally, you can check the response status to determine if the request was successful.

javascript
1const fetchData = async () => {
2	try {
3		const response = await fetch(
4			'https://jsonplaceholder.typicode.com/posts/1',
5			{
6				method: 'GET',
7				headers: {
8					'Content-Type': 'application/json',
9				},
10				params: {
11					title: 'foo',
12					body: 'bar',
13				},
14			}
15		);
16		// Check if the response status is OK (200)
17		if (response.status !== 200 || response.statusText !== 'OK') {
18			throw new Error(`Error: ${response.status} ${response.statusText}`);
19		}
20		const data = await response.json();
21		// check if data is valid
22		if (!data) {
23			throw new Error('Error: No data found');
24		}
25		// check if data is in expected format
26		if (typeof data !== 'object') {
27			throw new Error('Error: Invalid data format');
28		}
29		return data;
30	} catch (error) {
31		console.error('Fetch error:', error);
32		return null;
33	}
34};
35
36fetchData();

Streaming large responses

The Fetch API supports streaming large responses, allowing you to process data as it arrives. This is particularly useful for handling large files or real-time data streams.

javascript
1const fetchAndStitchJSON = async () => {
2  const response = await fetch(url);
3  const reader = response.body.getReader();
4  const decoder = new TextDecoder("utf-8");
5
6  let buffer = "";
7  let done = false;
8
9  while (!done) {
10    const { value, done: streamDone } = await reader.read();
11    done = streamDone;
12
13    if (value) {
14			console.log("Received chunk:", value);
15			// Decode and append the chunk to the buffer
16			buffer += decoder.decode(value, { stream: true });
17    }
18  }
19
20  try {
21    // Parse the complete JSON from the buffer
22    const jsonData = JSON.parse(buffer);
23    console.log("Parsed JSON:", jsonData);
24  } catch (error) {
25    console.error("Failed to parse JSON:", error);
26  }
27}
28
29fetchAndStitchJSON("https://jsonplaceholder.typicode.com/posts");

This receives the response in chunks and processes each chunk as it arrives.

javascript
1Received chunk: Uint8Array(3762) [
2   91,  10,  32,  32, 123,  10,  32,  32,  32,  32,  34, 117,
3  115, 101, 114,  73, 100,  34,  58,  32,  49,  44,  10,  32,
4   32,  32,  32,  34, 105, 100,  34,  58,  32,  49,  44,  10,
5   32,  32,  32,  32,  34, 116, 105, 116, 108, 101,  34,  58,
6   32,  34, 115, 117, 110, 116,  32,  97, 117, 116,  32, 102,
7   97,  99, 101, 114, 101,  32, 114, 101, 112, 101, 108, 108,
8   97, 116,  32, 112, 114, 111, 118, 105, 100, 101, 110, 116,
9   32, 111,  99,  99,  97, 101,  99,  97, 116, 105,  32, 101,
10  120,  99, 101, 112,
11  ... 3662 more items
12]
13
14Received chunk: Uint8Array(5445) [
15   32, 100, 111, 108, 111, 114, 101, 109, 113, 117, 101,  32,
16  110, 101, 113, 117, 101,  32, 102,  97,  99, 101, 114, 101,
17   92, 110,  97, 100,  32, 113, 117, 105,  32, 100, 111, 108,
18  111, 114, 117, 109,  32, 109, 111, 108, 101, 115, 116, 105,
19   97, 101,  32,  98, 101,  97, 116,  97, 101,  92, 110, 115,
20  101, 100,  32,  97, 117, 116,  32, 118, 111, 108, 117, 112,
21  116,  97, 115,  32, 116, 111, 116,  97, 109,  32, 115, 105,
22  116,  32, 105, 108, 108, 117, 109,  34,  10,  32,  32, 125,
23   44,  10,  32,  32,
24  ... 5345 more items
25]
26
27...
28

Tools like partial-json-parser can help with incrementally parsing JSON streams.

Cancelling in-flight requests

The Fetch API allows you to cancel in-flight requests using the AbortController interface. This is useful for aborting requests that are no longer needed, such as when a user navigates away from a page or when a component unmounts.

javascript
1const controller = new AbortController();
2const { signal } = controller;
3
4const fetchData = async () => {
5	try {
6		const response = await fetch(
7			'https://jsonplaceholder.typicode.com/posts/1',
8			{
9				method: 'GET',
10				headers: {
11					'Content-Type': 'application/json',
12				},
13				params: {
14					title: 'foo',
15					body: 'bar',
16				},
17				signal, // Abort signal
18			}
19		);
20		if (response.status !== 200 || response.statusText !== 'OK') {
21			throw new Error(`Error: ${response.status} ${response.statusText}`);
22		}
23		const data = await response.json();
24		return data;
25	} catch (error) {
26		if (error.name === 'AbortError') {
27			console.log('Fetch aborted');
28			return null;
29		}
30		console.error('Fetch error:', error);
31		return null;
32	}
33};
34
35fetchData();
36controller.abort(); // Abort the fetch request

Behind the seenes, the AbortController terminates the TCP connection to the server, which means that the request will not be processed by the server. This is important for performance and resource management.

Diagram Loading...

Endpoints can be configured to handle halfOpen connections. This means the server will continue trying to send data after acknowledging a FIN packet. This is useful for long-lived connections, such as WebSockets or HTTP/2 streams.

However, this is not the default behavior for most HTTP servers. Most servers will close the connection immediately after sending a FIN_ACK packet.

Conclusion

The Fetch API is a powerful tool for making HTTP requests in JavaScript. By mastering its features, including error handling, streaming, and cancellation, you can build robust and efficient web applications.

In this article