*
Previous async/await in JavaScript Error Handling in Javascript (try catch) Next

Fetch API in JavaScript

Fetch API (Calling External APIs)

The Fetch API is a modern interface for making HTTP requests in JavaScript. It provides a more powerful and flexible way to interact with resources over the network compared to older methods like XMLHttpRequest. It offers a powerful, flexible, and promise-based way to fetch resources from a server, making asynchronous operations more straightforward and cleaner.

Definition: The fetch() API is a modern JavaScript interface used to make HTTP requests to servers. It returns a Promise that resolves to the response of the request.

How it works

The fetch() method is a global function that takes one mandatory argument: the URL of the resource you want to retrieve. It returns a Promise that resolves to a Response object as soon as the server responds with headers.

The process typically involves two stages:

  • Request and Initial Response: Call fetch() with the URL. This returns a promise that resolves with a Response object. The promise only rejects on network failures, such as a lack of internet connection or a bad URL.
  • Handling the Data: The Response object doesn't contain the final data (e.g., JSON) directly. You must call a method on the Response object, such as response.json(), to parse the data. This returns a second promise that resolves with the final data.

Basic syntax with async/await

Using async/await is the most modern and readable way to use the Fetch API.

async function fetchPosts() {
  try {
    // Stage 1: Send the request and await the Response object
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');

    // Manually check if the HTTP status is ok (200-299)
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    // Stage 2: Parse the response body and await the JSON data
    const data = await response.json();
    
    console.log(data);
  } catch (error) {
    // Catch network errors and our custom HTTP status error
    console.error('Fetch error:', error);
  }
}

fetchPosts();

🔧 Syntax

fetch(url, options)
.then(response => response.json())
.then(data => {
  // handle the data
})
.catch(error => {
  // handle the error
});

💡 Example

fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => {
  if (!response.ok) {
    throw new Error("Network response was not ok");
  }
  return response.json();
})
.then(data => {
  console.log("Post title:", data.title);
})
.catch(error => {
  console.error("Fetch error:", error);
});

Performing different HTTP requests

By default, fetch() uses the GET method. You can specify a different HTTP method by passing an optional second argument—a configuration object.

POST request

async function createPost() {
  const newPost = {
    title: 'foo',
    body: 'bar',
    userId: 1,
  };

  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: JSON.stringify(newPost), // Convert the JavaScript object to a JSON string
  };

  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts', options);
    const result = await response.json();
    console.log('Post created:', result);
  } catch (error) {
    console.error('Error:', error);
  }
}

createPost();

✅ Advantages of the Fetch API

  • Built-in and modern: No need for external libraries
  • Promise-based: Works well with async/await
  • Supports streaming and advanced options
  • Works in most modern browsers
  • Promise-based: The use of promises simplifies the handling of asynchronous operations, eliminating the need for deeply nested callbacks.
  • Simple and intuitive: The syntax is clean and easy to understand, especially when using async/await.
  • Flexible: You can easily customize requests by setting headers, methods, and the request body.
  • Built-in: It's a standard web API and is supported in all modern browsers, so no external libraries are needed.
  • Streamlined handling of different data formats: Built-in methods like response.json(), response.text(), and response.blob() simplify the process of handling various response types.

❌ Disadvantages of the Fetch API

  • No built-in timeout or cancellation
  • Requires manual error handling for HTTP errors
  • Not supported in very old browsers (e.g., IE)
  • No HTTP error rejection: A fetch() promise only rejects on network errors. For HTTP error status codes like 404 or 500, the promise still resolves, and you must manually check the response.ok property.
  • Lack of built-in features: It does not have built-in support for request cancellation, progress tracking, or interceptors (functionality found in libraries like Axios).
  • Cross-origin security: Due to browser security policies (CORS), requests to a different domain may require specific headers from the server to be successful.

📌 When to Use

  • Fetching data from REST APIs
  • Submitting form data to a server
  • Loading external resources dynamically
  • Communicating with backend services

🚫 When Not to Use

  • In environments without Fetch support (use polyfills or Axios)
  • For complex request flows (consider libraries like Axios)
  • When you need request cancellation (use AbortController)

🧠 Best Practices

  • Always check response.ok before parsing
  • Use async/await for cleaner syntax
  • Handle errors with try...catch or .catch()
  • Use AbortController to cancel requests if needed
  • Validate and sanitize user input before sending requests

Best practices and precautions

  • Always handle errors: Don't rely on .catch() alone. Manually check response.ok or the status code to handle HTTP errors explicitly.
  • Use async/await: For better readability and a more synchronous feel, use async/await with try...catch for error handling.
  • Chain, don't nest: When using .then(), return the result of the next operation to avoid nesting.
  • Use Promise.all() for parallel requests: For multiple independent requests, use Promise.all() to fire them all at once rather than waiting for each one to complete sequentially.
  • Cancel requests with AbortController: To make a request cancellable, integrate the AbortController interface.
  • Remember response streams: Methods like response.json() consume the response body stream. If you need to read it multiple times, use response.clone() first.
Back to Index
Previous async/await in JavaScript Error Handling in Javascript (try catch) Next
*
*