DEV Community

Cover image for How To Use Fetch API In JavaScript
Udemezue John
Udemezue John

Posted on

How To Use Fetch API In JavaScript

Introduction.

I’ve spent a lot of time exploring JavaScript and learning the tricks that help me create cleaner, more efficient code. One tool that stands out is the Fetch API.

It lets me communicate with web servers and retrieve data in a modern, promise-based way.

This post is all about showing you how to use the Fetch API in JavaScript.

What Is the Fetch API?

The Fetch API is a built-in browser interface for making network requests.

It replaces older methods like XMLHttpRequest and offers a simpler, more powerful way to handle HTTP requests.

With Fetch, you can retrieve data from remote servers, submit forms, and interact with APIs—all with a few lines of code.

For example, to get data from a sample API, you might write:

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

This snippet sends a request to the provided URL, processes the JSON response, and logs the data.

The syntax is clean and easy to understand, making it a favorite for many developers.

Why Is the Fetch API Important?

I find that using the Fetch API offers several benefits:

  • Simplicity and Readability: The promise-based syntax helps avoid the callback hell that was common with older methods. This makes the code easier to read and debug.
  • Built-In Handling: Fetch comes with built-in support for handling responses, which means I can work with streams and data directly.
  • Better Error Handling: Although error handling with Fetch requires some extra steps, it still allows me to manage errors more gracefully compared to some older approaches.
  • Modern Features: Since Fetch is part of the modern JavaScript standard, it supports newer web features and integrates well with async/await syntax, making asynchronous code even cleaner.

For more detailed documentation, the Mozilla Developer Network (MDN) offers a great reference page on the Fetch API: MDN Fetch API.

Getting Started With the Fetch API

Let’s break down the basics with a simple example. Imagine you need to fetch user data from a server. Here’s a step-by-step guide:

1. Sending a Request.

I start by calling fetch() with the URL of the API. The function returns a promise that resolves to the response object.

fetch('https://jsonplaceholder.typicode.com/users')
  .then(response => {
    // Check if the request was successful
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(users => {
    // Work with the user data here
    console.log(users);
  })
  .catch(error => {
    // Handle any errors
    console.error('Fetch error:', error);
  });
Enter fullscreen mode Exit fullscreen mode

2. Processing the Response.

In the example above, once the promise resolves, I convert the response into JSON. This allows me to work with the data in JavaScript objects or arrays.

3. Handling Errors.

It’s important to check if the response is okay (using response.ok). If the request fails, I throw an error which is caught in the .catch() block.

4. Using Async/Await.

Many developers, including me, prefer the async/await syntax for its clarity. Here’s how the same code might look:

async function getUsers() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const users = await response.json();
    console.log(users);
  } catch (error) {
    console.error('Fetch error:', error);
  }
}

getUsers();

Enter fullscreen mode Exit fullscreen mode

This version feels more like regular synchronous code, even though it’s handling asynchronous operations.

Handling Errors and Improving Your Code

While the Fetch API is straightforward, error handling is crucial. Network requests can fail for many reasons, and I always aim to handle these failures gracefully.

Here are some tips:

  • Check the Response: Always check response.ok before processing the data. If the response isn’t OK, throw an error.
  • Catch Network Failures: Use the .catch() block (or a try/catch statement in async functions) to handle network errors.
  • Timeouts: The Fetch API doesn’t have a built-in timeout feature. I sometimes use helper functions or libraries to add timeout functionality if needed.
  • Custom Headers: When interacting with APIs, you might need to include custom headers (like authentication tokens). You can do this by passing an options object to fetch():
fetch('https://api.example.com/secure-data', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer your-token-here',
    'Content-Type': 'application/json'
  }
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

Advanced Uses of the Fetch API

Once you’re comfortable with basic GET requests, you can explore more advanced features:

POST, PUT, and DELETE Requests: The Fetch API supports all HTTP methods. For example, to send data to a server with a POST request:

fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'Fetch API Guide',
    body: 'Learning how to use the Fetch API in JavaScript is fun and practical.',
    userId: 1
  })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode
  • Streaming Responses: For large files or continuous data, the Fetch API supports streaming responses. This allows me to process data in chunks rather than waiting for the entire file.
  • AbortController: If I need to cancel a request (for example, if the user navigates away), I can use the AbortController API. This is especially useful in single-page applications to avoid unwanted network traffic.

FAQs

What is the main advantage of using the Fetch API over XMLHttpRequest?

The Fetch API uses promises, which leads to cleaner and more manageable code. It simplifies handling asynchronous requests and makes error handling more straightforward.

Can I use the Fetch API in all browsers?

Most modern browsers support Fetch, including Chrome, Firefox, Edge, and Safari. For older browsers, I might need to include a polyfill like whatwg-fetch.

How do I handle errors in Fetch?

I check if the response is successful using response.ok. If it’s not, I throw an error, which is then caught in the .catch() block or try/catch statement in async functions.

Is it possible to add custom headers to a Fetch request?

Yes, you can include custom headers by passing an options object with a headers property when calling fetch().

How do I use Fetch with async/await?

Wrap your fetch calls in an async function and use await to pause execution until the promise resolves. This makes the code look more like traditional synchronous code.

Further Resources

To dive deeper into the Fetch API and related topics, consider these resources:

  • Mozilla Developer Network (MDN): A comprehensive guide on the Fetch API, including examples and in-depth explanations. Check it out here.
  • WHATWG Fetch Standard: For those interested in the technical details and underlying standard, the specification is available on the WHATWG website.
  • JavaScript.info: This site offers tutorials and examples that cover the basics of Fetch as well as more advanced concepts. Visit JavaScript.info for more information.
  • Online Courses and Tutorials: Platforms like Udemy and freeCodeCamp offer video tutorials and practical projects that help in understanding real-world usage of Fetch in JavaScript.

Conclusion

The Fetch API is a powerful tool that simplifies working with network requests in JavaScript.

I’ve learned that it not only makes the code cleaner with promises and async/await but also provides the flexibility to handle errors, custom headers, and even streaming data.

Whether you’re working on a small personal project or a large-scale web application, mastering Fetch can make your life easier and your code more efficient.

I hope this guide has helped you understand the Fetch API better. It’s all about taking that first step into making modern, clean network requests and gradually building your knowledge with practice and exploration.

So, how will you use the Fetch API in JavaScript in your next project?

Top comments (3)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Check the Response: Always check response.ok before processing the data. If the response isn’t OK, throw an error.

Terrible advise.

Collapse
 
theudemezue profile image
Udemezue John

What then do you advice?

Collapse
 
webjose profile image
José Pablo Ramírez Vargas • Edited

Not throwing.

Review your code:

async function getUsers() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/users');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const users = await response.json();
    console.log(users);
  } catch (error) {
    console.error('Fetch error:', error);
  }
}
Enter fullscreen mode Exit fullscreen mode

In this code, you branch (you use an IF) to throw. This forces the consuming code to then use a try..catch:

try {
  const users = await getUsers();
}
catch {
  // Handle error, like showing an error message to the user of the application.
}
Enter fullscreen mode Exit fullscreen mode

If you didn't throw, and simply returned a more appropriate response, then everything gets better.

I know, the problem is the data typing: The response body may contain different data depending on the status code returned. For instance, 400 might come with a list of errors in the body.

For this, I created dr-fetch. With this guy, we can re-write getUsers():


// In a separate module, create the fetcher object:
import { DrFetch } from 'dr-fetch';
export const fetcher = new DrFetch();

// Import the fetcher:
import { fetcher } from './fetcher.js';

function getUsers() {
  return fetcher
    .for<200, User[]>()
    .for<400, ValidationError[]>()
    .fetch('https://jsonplaceholder.typicode.com/users');
}
Enter fullscreen mode Exit fullscreen mode

The response of this version allows the consumer to do this instead:

const usersResponse = await getUsers();
if (!usersResponse.ok) {
  // Show generic error message.
}
else {
  // The list of users is in usersResponse.body.
}
Enter fullscreen mode Exit fullscreen mode

Or you could branch by status code:

const usersResponse = await getUsers();
if (usersResponse.status = 400) {
  // Show specialized UI that lists the errors, which are in usersResponse.body.
}
else if (!usersResponse.ok) {
  // Unexpected status code.  See how much better this is?  We can identify more accurately what happens.
}
else {
  // The list of users is in usersResponse.body.
}
Enter fullscreen mode Exit fullscreen mode

If you compare this version with your proposed version, your proposed version is:

  • Using an IF to possibly throw.
  • Forcing the consumer to use try..catch.
  • Obscuring the problem: Is the error because of a network communication error, or because of an unexpected status code?

I understand. Before I made dr-fetch there was nothing out there to help users write code the best possible way. Now there is. 😄