in

JavaScript Fetch API Explained in Depth

default image

Hi there! As a web developer and API enthusiast, I‘m excited to provide you with a comprehensive, friendly overview of the JavaScript Fetch API. This powerful feature allows us to interact with servers directly from client-side JavaScript.

There‘s a lot to cover, so grab a cup of coffee and let‘s dive in!

What is the Fetch API and Why Should You Care?

The Fetch API provides an interface for fetching resources from across the network. It allows us to make HTTP requests directly from JavaScript to interact with APIs, servers, and databases.

Here are some key reasons why the Fetch API is useful:

  • It provides a simpler, more intuitive way to make HTTP calls compared to the older XMLHttpRequest API. The syntax feels more natural using modern JavaScript promises.
  • It integrates seamlessly with many new JavaScript features like async/await for writing asynchronous code.
  • You can use it to fetch resources from anywhere – APIs, databases, file servers, etc. right from the browser.
  • It supports newer web technologies like CORS out of the box for cross-origin resource handling.
  • The API is versatile enough to handle different types of requests like GET, POST, PUT, DELETE seemlessly.

Overall, the Fetch API solves many of the shortcomings of previous options like XMLHttpRequest and opens up a whole new world of possibilities for web developers!

A Quick Feature Overview

Before we dive into code samples, let‘s highlight some of the cool capabilities of Fetch:

  • Intuitive syntax – the fetch() method provides an easy way to make requests.
  • Promise-based – Fetch uses promises instead of callbacks for cleaner async code.
  • Making requests – Supports different methods like GET, POST, PUT, DELETE.
  • Adding headers – Set custom headers for authorization, CORS, etc.
  • Sending body data – Easily send JSON, FormData, and other types of data.
  • Handling responses – Get back detailed response data with status, headers, and body.
  • Automatic parsing – Fetch automatically parses JSON responses for you.

As you can see, the API provides a very versatile set of features! Now let‘s go over some examples.

Browser Compatibility for Fetch

Before we start using Fetch, let‘s quickly go over which browsers support it:

  • Fetch is supported natively in all modern browsers including Chrome 42+, Firefox 39+, Edge 14+, and Safari 10.1+.
  • Older browsers like IE11 do not support Fetch at all.
  • Currently, around 95% of global users have a browser that supports Fetch.

So you‘re probably fine using it directly in most cases. But for full support, you may want to include a polyfill like this one. With the polyfill added, you can use Fetch seamlessly in any browser.

Now let‘s jump into some examples!

Making a Simple GET Request with Fetch

Let‘s start with a simple GET request:

fetch(‘/api/users‘)
  .then(response => {
    // handle response  
  })

See how easy that was! We don‘t have to mess around with XMLHttpRequest. Just call fetch() passing the URL and handle the response.

The fetch() method returns a promise that resolves once the request completes. This allows us to chain .then() and .catch() to deal with the result.

Here is an example using async/await syntax:

async function getUsers() {

  const response = await fetch(‘/api/users‘);

  if(!response.ok) { // check for errors
    throw new Error(‘Failed to fetch users‘);
  }

  const data = await response.json(); // parse response data

  console.log(data); // array of user objects 

}

getUsers();

The async/await approach makes the code much cleaner compared to promise chaining. We await each step and use standard try/catch to handle errors.

Next, let‘s look at sending some data along with our request.

Making POST Requests with Fetch

In addition to GET requests, we can easily make POST, PUT, and DELETE requests using fetch.

For example, here is how to make a POST request:

const response = await fetch(‘/api/users‘, {
  method: ‘POST‘, 
  body: JSON.stringify({
    name: ‘John‘,
    age: 30
  })
});

To make a POST request, we pass the body data and set the method option to ‘POST‘. The body can be a string or FormData object.

The API accepts our input and returns a promise with the response.

Here is an example POST request to login a user:

const response = await fetch(‘/login‘, {
  method: ‘POST‘,
  headers: {
    ‘Content-Type‘: ‘application/json‘
  },
  body: JSON.stringify({
    username: ‘john123‘,
    password: ‘xxxxxx‘ 
  })
});

const data = await response.json();

// logged in 

We can use the same fetch approach to make PUT, DELETE, and other types of requests as well. The syntax is very similar.

Setting Custom Request Headers with Fetch

Some APIs require specific headers to be set. For example, an authorization header:

fetch(url, {
  headers: {
    Authorization: `Bearer ${token}` 
  }
})  

We can pass a headers property in the options to set any custom headers we need.

Some other common use cases for headers:

  • Specifying content type – Content-Type, Accept etc.
  • CORS/Cross-origin related – Origin, Cross-Origin etc.
  • Cookies/credentials – Credentials, X-Requested-With etc.
  • Security – X-Frame-Options, Content-Security-Policy etc.

So with headers, we can customize requests to match exactly what the API needs.

Advanced Options for Controlling Fetch Requests

In addition to headers, methods and body, the Fetch API supports many other options to control requests:

fetch(url, {

  // HTTP method - GET, POST, PUT, DELETE 
  method: ‘GET‘,  

  // request body 
  body: null, 

  // cache handling - *default, no-cache, reload, force-cache, only-if-cached
  cache: ‘no-cache‘, 

  // credentials - include, *same-origin, omit 
  credentials: ‘include‘,

  // redirect handling - *follow, error, manual
  redirect: ‘follow‘,

  // mode - cors, no-cors, *same-origin, navigate
  mode: ‘cors‘, 

  // ... other advanced options

});

These options allow you to control caching, redirects, credentials, CORS mode, and more.

Some advanced use cases are:

  • Enabling CORS for cross-origin requests
  • Adding cache busting for fresher requests
  • Changing redirect behavior
  • Sending cookies and credentials
  • Controlling caching policies

The options provide very fine-grained control over Fetch requests!

Handling Fetch Errors Gracefully

As with any network requests, errors can happen frequently. Let‘s go over some potential errors and how to handle them properly:

Network Errors

Issues like no connectivity, DNS failure, server down etc:

try {
  const response = await fetch(url);
} catch (error) {
  // Catches network errors
}

HTTP Errors

404, 403, 500, and other HTTP status codes:

const response = await fetch(url);

if (!response.ok) {
  // Handles HTTP errors
}

CORS & Cross Origin Issues

APIs need to enable CORS. If not, opaque cross origin errors will occur:

const response = await fetch(url);

if (response.type === ‘cors‘) {
  // Handle cross origin error
}

So always handle errors and unsuccessful status codes properly!

Real World Examples and Use Cases

Now that you know how to use Fetch, let‘s go over some practical examples:

Single Page Apps

Fetch is commonly used in SPAs for calling APIs:

// Fetch data on load
const response = await fetch(‘/api/todos‘);
const todos = await response.json();

// Render initial UI
renderUI(todos);

// Get realtime updates  
setInterval(async () => {

  const response = await fetch(‘/api/todos/updates‘);
  const newTodos = await response.json();

  updateUI(newTodos);

}, 5000);

We can fetch data and seamlessly update the UI as needed.

Submitting Forms

Easily submit forms and handle responses:

const form = document.querySelector(‘form‘);

form.addEventListener(‘submit‘, async event => {

  event.preventDefault();

  const response = await fetch(‘/contact‘, {
    method: ‘POST‘,
    body: new FormData(form)
  });

  showSuccessMessage();

});

File Uploads

Thanks to FormData, we can also upload files:

const input = document.querySelector(‘input[type="file"]‘);

const data = new FormData();
data.append(‘file‘, input.files[0]);

fetch(‘/uploads‘, {
  method: ‘POST‘,
  body: data
});

Authentication & Sessions

Fetch allows implementing login/auth functionality:

// Login 
const response = await fetch(‘/login‘, {
  method: ‘POST‘,
  body: {
    username: ‘john123‘,
    password: ‘xxxx‘
  }
});

const { token } = await response.json();

// Attach token to subsequent requests
fetch(‘/user/123‘, {
  headers: {
    Authorization: `Bearer ${token}`
  }
});

We can use Fetch for so many real-world use cases like these!

Wrapping Up

We‘ve covered a lot of ground here! To recap:

  • The Fetch API provides an easy way to fetch resources from the network using JavaScript.

  • It has a simple promise-based syntax that is easy to use.

  • Fetch supports all kinds of HTTP requests like GET, POST, PUT etc.

  • You can easily add headers, body, and other options to customize requests.

  • It handles JSON parsing automatically.

  • Be sure to handle errors and unsuccessful responses properly.

  • There are many great real-world use cases like submitting forms, authentication, uploading files etc.

I hope this guide gave you a comprehensive overview of getting started with the powerful Fetch API! Let me know if you have any other questions.

Happy fetching!

Written by