Skip to content
FLAVIO COPES
flaviocopes.com
2026

The Fetch API

By

Learn how to make HTTP requests with the Fetch API, check response errors, read response bodies, send JSON, set headers, and cancel a request.

~~~

Introduction to the Fetch API

The Fetch API is the standard way to make HTTP requests from JavaScript.

You call fetch(), and it returns a Promise that resolves to a Response object. You can then read the response as JSON, text, a blob, or another supported format.

Fetch is the modern replacement for XMLHttpRequest. It is available in browser windows and workers. You can find the complete API in the MDN Fetch reference.

Using Fetch

The simplest GET request looks like this:

fetch('/file.json')

This makes an HTTP request for file.json on the same origin.

Let’s read the response as JSON:

fetch('./file.json')
  .then((response) => response.json())
  .then((data) => console.log(data))

Calling fetch() returns a promise. The first callback receives a Response. The json() method reads its body and returns another Promise.

You can also use await:

async function getData() {
  const response = await fetch('./file.json')
  const data = await response.json()
  console.log(data)
}

getData()

Catching errors

A Fetch Promise rejects for network failures and invalid requests. It does not reject just because the server returns 404 or 500.

Check response.ok before reading the body, as shown in the MDN Fetch error-handling guide:

async function getData() {
  try {
    const response = await fetch('./file.json')

    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`)
    }

    const data = await response.json()
    console.log(data)
  } catch (error) {
    console.error(error)
  }
}

Response Object

The Response Object returned by a fetch() call contains all the information about the request and the response of the network request.

Metadata

headers

Accessing the headers property on the response object gives you the ability to look into the HTTP headers returned by the request:

fetch('./file.json').then((response) => {
  console.log(response.headers.get('Content-Type'))
  console.log(response.headers.get('Date'))
})

Request headers for fetch

status

This property is the numeric HTTP response status, such as 200 or 404.

fetch('./file.json').then((response) => console.log(response.status))

statusText

statusText contains the status message returned by the server. Do not depend on it for application logic: HTTP/2 does not define status messages, so it can be empty. Use status or ok instead.

fetch('./file.json').then((response) => console.log(response.statusText))

url

url contains the final URL of the resource that was fetched.

fetch('./file.json').then((response) => console.log(response.url))

Body content

A response has a body, accessible using several methods:

All those methods return a promise. Examples:

fetch('./file.json')
  .then((response) => response.text())
  .then((body) => console.log(body))
fetch('./file.json')
  .then((response) => response.json())
  .then((body) => console.log(body))

Get JSON

The same can be written using an async function:

async function getData() {
  const response = await fetch('./file.json')
  const data = await response.json()
  console.log(data)
}

getData()

Request Object

The Request object represents a resource request, and it’s usually created using the new Request() API.

Example:

const req = new Request('/api/todos')

The Request object offers several read-only properties to inspect the request:

It also exposes methods including json(), text(), and formData() to read the request body.

The full API can be found at https://developer.mozilla.org/docs/Web/API/Request

Request headers

You can set request headers using a Headers object:

const headers = new Headers()
headers.append('Content-Type', 'application/json')

or:

const headers = new Headers({
  'Content-Type': 'application/json',
})

To attach the headers to the request, we use the Request object, and pass it to fetch() instead of passing the URL.

Instead of:

fetch('./file.json')

we do

const request = new Request('./file.json', {
  headers: new Headers({
    'Content-Type': 'application/json',
  }),
})
fetch(request)

You can also query it:

headers.has('Content-Type')
headers.get('Content-Type')

and we can delete a header that was previously set:

headers.delete('X-My-Custom-Header')

POST Requests

Fetch also supports other HTTP methods, including POST, PUT, PATCH, and DELETE.

Here is a JSON POST request:

async function createTodo() {
  const response = await fetch('/api/todos', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      title: 'Learn the Fetch API',
    }),
  })

  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`)
  }
}

createTodo()

How to cancel a fetch request

You can cancel a request using AbortController.

Pass its signal to fetch():

const controller = new AbortController()
const signal = controller.signal

fetch('./file.json', { signal })

This cancels it after 5 seconds:

setTimeout(() => controller.abort(), 5 * 1000)

When the controller aborts, fetch() rejects with a DOMException named AbortError:

fetch('./file.json', { signal })
  .then((response) => response.text())
  .then((text) => console.log(text))
  .catch((err) => {
    if (err.name === 'AbortError') {
      console.error('Fetch aborted')
    } else {
      console.error('Another error', err)
    }
  })
~~~

Related posts about platform: