How to use JavaScript fetch API

The JavaScript Fetch API is a powerful tool for making HTTP requests easily for fetching resources across the web. With its clean and simple syntax, fetch integrates seamlessly with Promises and async/await for handling asynchronous operations.

Whether you need to fetch JSON data from a RESTful API or interact with various API endpoints, fetch simplifies the process.

In this article, I’ll guide you through the essentials of using the Fetch API, including error handling, setting headers, and understanding request and response objects to boost your web development projects.

Basic Syntax and Usage

Basic Fetch API Syntax

fetch() function

The fetch() function is the cornerstone of making network requests with JavaScript. It’s a modern alternative to XMLHttpRequest, providing a simpler and more powerful way to work with network operations.

The fetch() function takes two parameters:

  • URL: The resource endpoint to interact with.
  • Options: An optional object to configure the request (like method, headers, body).

Parameters: URL and options

Before diving into examples, let’s look at the fetch() function syntax:

fetch(url, options)
  • url: This is a string representing the resource you want to fetch.
  • options: This is an object that can contain various settings such as methodheadersbody, etc.

Here’s how these parameters break down:

  • method: Defines the type of request (GET, POST, PUT, DELETE). Defaults to GET.
  • headers: Contains any headers you want to add to your request.
  • body: Provides data that you want to send with the request, typically used with POST or PUT.

Example of a Basic Fetch Request

Code example

To better understand the practical application, here’s a basic example of making a GET request to fetch user data:

fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error fetching data:', error));

Explanation of the example

Let’s break down what happens in this example:

  1. fetch(‘https://jsonplaceholder.typicode.com/users’): This line initiates a GET request to the specified URL.
  2. .then(response => response.json()): Once the request completes, the response object is passed to this function. response.json() process parses the JSON-formatted response body and returns a promise.
  3. .then(data => console.log(data)): This function handles the parsed JSON data, which in this case is logged to the console.
  4. .catch(error => console.error(‘Error fetching data:’, error)): If an error occurs at any stage (such as network issues), this function catches and logs the error.

Working with Fetch API provides an easier way to interact with RESTful APIs, handling network requests with a syntax that promotes clarity and better error management.

The Fetch API employs promises, allowing you to handle asynchronous operations more seamlessly. This methodology enhances the readability and maintainability of your code, marking a clear improvement over older approaches like XMLHttpRequest.

Making Different Types of Requests

GET Requests

Definition and use cases

GET requests are the most common type in web development. They are used to retrieve data from a server without making any changes to the data on the server. Think of fetching user profiles, loading blog posts, or displaying product listings.

Example: Fetching User Data

Code example
fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Explanation and breakdown
  1. fetch(‘https://jsonplaceholder.typicode.com/users’): Initiates a GET request to the provided URL.
  2. .then(response => response.json()): Converts the response to a JSON object.
  3. .then(data => console.log(data)): Logs the retrieved user data to the console.
  4. .catch(error => console.error(‘Error:’, error)): Catches and logs any errors encountered during the fetch.

POST Requests

Definition and use cases

POST requests are used to send data to the server, typically for creating or updating resources. Common use cases include submitting forms, adding new entries, or uploading files.

Example: Sending Form Data

Code example
fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'foo',
    body: 'bar',
    userId: 1
  })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Explanation and breakdown
  1. fetch(‘https://jsonplaceholder.typicode.com/posts’, { … }): Starts a POST request to the URL with specified options.
  2. method: ‘POST’: Defines the HTTP method as POST.
  3. headers: { ‘Content-Type’: ‘application/json’ }: Specifies that the request body contains JSON.
  4. body: JSON.stringify({ title: ‘foo’, body: ‘bar’, userId: 1 }): Converts the JavaScript object to a JSON string to send in the request body.
  5. .then(response => response.json()): Converts the server response to a JSON object.
  6. .then(data => console.log(data)): Logs the response data to the console.
  7. .catch(error => console.error(‘Error:’, error)): Catches and logs any errors.

Handling Other HTTP Methods

PUT requests

PUT requests are used to update an existing resource on the server. They send data to the server to replace the target resource’s current representation.

Example:

fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    id: 1,
    title: 'updated title',
    body: 'updated body',
    userId: 1
  })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

DELETE requests

DELETE requests are used to remove a resource from the server. They instruct the server to delete the specified resource.

Example:

fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'DELETE'
})
  .then(response => {
    if (response.ok) {
      console.log('Resource deleted');
    } else {
      console.error('Error:', response.statusText);
    }
  })
  .catch(error => console.error('Error:', error));

Handling Responses

Response Object

Properties and methods

The response object is returned when a fetch request is completed. It contains several useful properties and methods to interact with the response from the server.

  • Properties:
    • response.ok: Indicates if the request was successful (status in the range 200–299).
    • response.status: The HTTP status code of the response.
    • response.statusText: The status message associated with the status code.
    • response.headers: The headers associated with the response.
  • Methods:
    • response.json(): Returns a promise that resolves to the result of parsing the body text as JSON.
    • response.text(): Returns a promise that resolves to the result of parsing the body text as a string.
    • response.blob(): Returns a Blob object, which represents binary data.
    • response.arrayBuffer(): Returns an ArrayBuffer object, which represents a generic, fixed-length raw binary data buffer.

Checking response status

It’s important to check the response status to ensure the request was successful. This can be easily done using the response.ok property.

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

Parsing Response Data

JSON responses

Most often, the server will respond with JSON data. Using the response.json() method will parse this data into a JavaScript object.

fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => response.json()) 
  .then(data => console.log(data)) 
  .catch(error => console.error('Error:', error));

Text responses

Sometimes, you might receive plain text from the server. For these cases, the response.text() method is handy.

fetch('https://example.com/text-response')
  .then(response => response.text())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Blob and ArrayBuffer responses

For binary data like images or files, the response.blob() or response.arrayBuffer() methods are used:

  • Blob: Represents raw binary data. Useful for handling file data.
fetch('https://example.com/image')
  .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:', error));
  • ArrayBuffer: Represents a low-level binary data buffer.
fetch('https://example.com/data')
  .then(response => response.arrayBuffer())
  .then(buffer => {
    // Handle the ArrayBuffer data
    console.log(buffer);
  })
  .catch(error => console.error('Error:', error));

Example of Parsing JSON Data

Code example

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

Explanation and breakdown

  1. fetch(‘https://jsonplaceholder.typicode.com/users’): Initiates the request to fetch user data.
  2. .then(response => { … }): Processes the response.
  3. if (!response.ok) { throw new Error(‘Network response was not ok’); }: Checks if the response status is OK, if not, an error is thrown.
  4. return response.json();: Converts the response to JSON.
  5. .then(data => console.log(data)): Logs the parsed JSON data.
  6. .catch(error => console.error(‘Error:’, error)): Catches and logs any errors that occur during the fetch or the processing of the response.

Error Handling in Fetch API

Importance of Error Handling

Handling errors effectively is crucial in web development. Ignoring error handling can lead to poor user experiences, like missing data or broken functionality without any feedback. When working with Fetch API, robust error handling ensures that users are informed about issues and helps in debugging problems efficiently.

Using the catch() Method

Basic error handling

The .catch() method is an easy way to handle errors in a promise chain. It catches any errors that occur in the preceding promises.

fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Example: Enhanced Error Handling

Code example
fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'TypeError') {
      console.error('Network error or resource not found:', error);
    } else {
      console.error('An unexpected error occurred:', error);
    }
  });
Explanation and breakdown
  1. fetch(‘https://jsonplaceholder.typicode.com/users’): Initiates the network request.
  2. .then(response => { … }): Handles the response object.
  3. if (!response.ok) { throw new Error(‘Network response was not ok’); }: Throws an error if the response status is not in the range 200-299.
  4. return response.json();: Parses the JSON response.
  5. .then(data => console.log(data)): Logs the parsed data.
  6. .catch(error => { … }): Enhanced error handling:
    • Checks if the error is a TypeError, which indicates network issues or resource not found.
    • Otherwise, logs a generic error message.

Using try/catch with Async/Await

Using async/await can make your code cleaner and easier to read. Error handling with try/catch in async/await syntax offers a more synchronous feel to asynchronous code.

Code example

async function fetchData() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    console.log(data);
  } catch (error) {
    if (error.name === 'TypeError') {
      console.error('Network error or resource not found:', error);
    } else {
      console.error('An unexpected error occurred:', error);
    }
  }
}

fetchData();

Explanation and breakdown

  1. async function fetchData() { … }: Defines an asynchronous function.
  2. try { … } catch (error) { … }: Encapsulates the fetch logic in a try block and handles errors in the catch block.
  3. const response = await fetch(‘https://jsonplaceholder.typicode.com/users‘);: Awaits the fetch request.
  4. if (!response.ok) { throw new Error(‘Network response was not ok’); }: Checks the response status.
  5. const data = await response.json();: Parses the JSON data.
  6. console.log(data);: Logs the data to the console.
  7. catch (error) { … }: Handles any errors:
    • Checks if the error is a TypeError for network issues.
    • Logs other unexpected errors.

Advanced Fetch API Usage

Handling Query Parameters

Definition and use cases

Query parameters are used to filter or modify the data fetched from an API. Think of them like search criteria added to the URL to pull specific information. This is useful for tasks like fetching search results, sorting data, or applying filters.

Example: Filtering Data with Query Parameters

Code example
const baseUrl = 'https://jsonplaceholder.typicode.com/users';
const params = new URLSearchParams({ username: 'Bret' });

fetch(`${baseUrl}?${params.toString()}`)
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Explanation and breakdown
  1. const baseUrl = ‘https://jsonplaceholder.typicode.com/users‘;: Defines the base URL.
  2. const params = new URLSearchParams({ username: ‘Bret’ });: Creates query parameters to filter the results by username.
  3. fetch(${baseUrl}?${params.toString()}): Constructs the full URL with query parameters and initiates the request.
  4. .then(response => response.json()): Parses the JSON response.
  5. .then(data => console.log(data)): Logs the filtered data.
  6. .catch(error => console.error(‘Error:’, error)): Handles any errors.

Authentication

Importance of authentication

When accessing protected resources or APIs, including API keys or tokens in your requests is crucial. Authentication ensures that only authorized users can access certain data or services.

Including API keys in headers

A common method of authentication is using Bearer tokens in the request headers. This token-based authentication is secure and widely adopted.

Example: Using Bearer Tokens
Code example
const apiKey = 'your_api_key_here';

fetch('https://example.com/protected-resource', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  }
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Explanation and breakdown
  1. const apiKey = ‘your_api_key_here’;: Stores the API key.
  2. fetch(‘https://example.com/protected-resource’, { … }): Initiates the fetch request to a protected resource.
  3. method: ‘GET’: Sets the HTTP method to GET.
  4. headers: { ‘Authorization’: Bearer ${apiKey}, ‘Content-Type’: ‘application/json’ }: Adds the Authorization header with the Bearer token.
  5. .then(response => response.json()): Parses the JSON response.
  6. .then(data => console.log(data)): Logs the protected data.
  7. .catch(error => console.error(‘Error:’, error)): Handles any errors.

Aborting Requests

Using AbortController

Sometimes, you may need to cancel a network request before it completes. This is where AbortController becomes invaluable, allowing you to abort a fetch request when necessary.

Example: Aborting a Fetch Request
Code example
const controller = new AbortController();
const signal = controller.signal;

fetch('https://jsonplaceholder.typicode.com/users', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Fetch aborted');
    } else {
      console.error('Error:', error);
    }
  });

// Abort the request after 1 second
setTimeout(() => controller.abort(), 1000);
Explanation and breakdown
  1. const controller = new AbortController();: Creates a new AbortController instance.
  2. const signal = controller.signal;: Gets the associated signal.
  3. fetch(‘https://jsonplaceholder.typicode.com/users’, { signal }): Initiates the fetch request with the abort signal.
  4. .then(response => response.json()): Parses the JSON response.
  5. .then(data => console.log(data)): Logs the data if the request completes.
  6. .catch(error => { … }): Handles errors, checking if they are abort errors.
  7. setTimeout(() => controller.abort(), 1000);: Aborts the fetch request after one second.

Asynchronous Programming with Fetch API

Understanding Asynchronous Nature of Fetch

Explanation of promises

Promises are a fundamental part of modern JavaScript, especially when dealing with asynchronous operations like network requests. A promise represents a value that may be available now, or in the future, or never.

In the context of Fetch API, promises help manage asynchronous tasks like making HTTP requests without blocking the main thread, ensuring a smooth user experience.

When you use the fetch() function, it returns a promise that resolves to the response object once the request completes.

Chaining promises

Promise chaining allows you to perform a sequence of asynchronous operations. Each .then() in a promise chain handles the output of the previous promise and passes it to the next, creating a clean and manageable flow of operations.

Using Async/Await for Fetch Requests

Syntax and benefits

Async/await is a newer syntax for handling asynchronous operations. It makes your code look synchronous, making it easier to read and write.

By using async functions and await, you can handle promises more elegantly compared to the traditional chaining with .then() and .catch().

Benefits include:

  • Improved readability: The code looks and behaves more like synchronous code.
  • Error handling: Easier and more intuitive with try and catch blocks.
  • Maintenance: Simplifies complex promise chains.

Example: Chaining Multiple Requests

Code example
async function fetchData() {
  try {
    const response1 = await fetch('https://jsonplaceholder.typicode.com/users/1');
    if (!response1.ok) {
      throw new Error('Network response was not ok');
    }
    const user = await response1.json();

    const response2 = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${user.id}`);
    if (!response2.ok) {
      throw new Error('Network response was not ok');
    }
    const posts = await response2.json();

    console.log('User:', user);
    console.log('Posts:', posts);
  } catch (error) {
    console.error('Error:', error);
  }
}

fetchData();
Explanation and breakdown
  1. async function fetchData() { … }: Defines an asynchronous function to handle the fetch operations.
  2. try { … } catch (error) { … }: Wraps the fetch logic in a try block and catches any errors.
  3. const response1 = await fetch(‘https://jsonplaceholder.typicode.com/users/1’);: Awaits the first fetch request to get user data.
  4. if (!response1.ok) { throw new Error(‘Network response was not ok’); }: Checks if the request was successful.
  5. const user = await response1.json();: Parses the user data to JSON.
  6. const response2 = await fetch(https://jsonplaceholder.typicode.com/posts?userId=${user.id});: Awaits the second fetch request to get posts for the user.
  7. if (!response2.ok) { throw new Error(‘Network response was not ok’); }: Checks if the second request was successful.
  8. const posts = await response2.json();: Parses the post data to JSON.
  9. console.log(‘User:’, user);: Logs the user data.
  10. console.log(‘Posts:’, posts);: Logs the posts data.

FAQ On How To Use JavaScript Fetch API

How to Use JavaScript Fetch API

The JavaScript Fetch API is a powerful tool for making HTTP requests easily for fetching resources across the web. With its clean and simple syntax, fetch integrates seamlessly with Promises and async/await for handling asynchronous operations.

Whether you need to fetch JSON data from a RESTful API or interact with various API endpoints, fetch simplifies the process.

In this article, I’ll guide you through the essentials of using the Fetch API, including error handling, setting headers, and understanding request and response objects to boost your web development projects.

What is the JavaScript Fetch API?

The Fetch API provides an easy way to make network requests just like XMLHttpRequest but with a more powerful and flexible feature set. It’s part of the JavaScript standard, so it’s widely supported in modern browsers. Essentially, fetch simplifies interacting with server-side APIs.

How do I make a basic GET request with the Fetch API?

Making a GET request is straightforward. Just call fetch('your-api-url') and then use .then(response => response.json()) to handle the response. This is your go-to for fetching JSON data from any URL endpoints you want to interact with. Easy and clean.

How do you handle errors in Fetch API?

Use the .catch(error => console.error('Error:', error)) method after your .then() chain to catch errors that might occur. Also, always check the response.ok property to handle HTTP status codes properly. Proper error handling ensures you catch issues early on.

Can Fetch API send POST requests?

Absolutely. You can use the Fetch API to make POST requests by specifying the method in the fetch options. Like this: fetch('your-api-url', { method: 'POST', body: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } }). It’s the go-to for HTTP POST requests.

What are the benefits of using Promises with Fetch?

Using Promises with Fetch makes handling asynchronous operations smoother. You can chain .then() to manage sequential steps and .catch() for errors, making it far more readable than old callback-based approaches. This is especially useful for complex asynchronous JavaScript operations.

How does Fetch API work with async/await?

With async/await, the Fetch API becomes easier to read and manage. You can write const response = await fetch('your-api-url'); followed by const data = await response.json();. This makes your asynchronous code look synchronous and greatly cleans up your JavaScript.

How can I set headers using the Fetch API?

Headers can be set in the fetch options object. Use the headers property like this: fetch('your-api-url', { headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token' } }). Custom headers can be critical for API authentication and CORS.

How do you read the response in Fetch API?

You read the response by calling response.json() when expecting a JSON response, or response.text() for plain text. The response object provides various methods to parse different content types. This flexibility aids in working with diverse network requests.

Is Fetch API better than XMLHttpRequest?

While it’s not accurate to say one is definitively better, the Fetch API offers a more modern, streamlined approach. It is part of the modern JavaScript standards and eliminates many of the headaches associated with XMLHttpRequest, making it the preferred choice for many developers.

How can the Fetch API handle multiple requests?

To handle multiple requests, you can use Promise.all([fetch(url1), fetch(url2)]) to run them in parallel and then .then(responses => responses.map(r => r.json())) to process them. This is particularly useful when you need to make multiple HTTP requests and aggregate the results.

Conclusion

Mastering how to use JavaScript Fetch API can significantly elevate your web development skills. Whether you need to make HTTP requests, handle JSON data, or integrate with a RESTful API, the Fetch API simplifies the whole process.

By adopting async/await and Promises, you can make your code more readable and efficient. Remember the basics: handle errors, set appropriate headers, and manage request and response objects carefully.

This newfound knowledge not only streamlines interacting with server-side APIs but also ensures your applications are modern and efficient, truly reflecting the capabilities of modern JavaScript.

If you liked this article about how to use JavaScript fetch API, you should check out this article about how to handle events in JavaScript.

There are also similar articles discussing how to make AJAX calls with JavaScripthow to create an object in JavaScripthow to use JavaScript promises, and how to write asynchronous JavaScript.

And let’s not forget about articles on how to create a JavaScript classhow to implement JavaScript ES6 featureshow to use JavaScript for form validation, and how to add event listeners in JavaScript.

By Bogdan Sandu

Bogdan is a seasoned web designer and tech strategist, with a keen eye on emerging industry trends. With over a decade in the tech field, Bogdan blends technical expertise with insights on business innovation in technology. A regular contributor to TMS Outsource's blog, where you'll find sharp analyses on software development, tech business strategies, and global tech dynamics.

Exit mobile version