# The Fetch API

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

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2018-02-02 | Updated: 2026-07-18 | Topics: [Web Platform](https://flaviocopes.com/tags/platform/) | Canonical: https://flaviocopes.com/fetch-api/

<!-- TOC -->

- [Introduction to the Fetch API](#introduction-to-the-fetch-api)
- [Using Fetch](#using-fetch)
  - [Catching errors](#catching-errors)
- [Response Object](#response-object)
  - [Metadata](#metadata)
    - [headers](#headers)
    - [status](#status)
    - [statusText](#statustext)
    - [url](#url)
  - [Body content](#body-content)
- [Request Object](#request-object)
- [Request headers](#request-headers)
- [POST Requests](#post-requests)
- [How to cancel a fetch request](#how-to-cancel-a-fetch-request)

<!-- /TOC -->

## 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](https://flaviocopes.com/xhr/). It is available in browser windows and workers. You can find the complete API in the [MDN Fetch reference](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

## Using Fetch

The simplest GET request looks like this:

```js
fetch('/file.json')
```

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

Let's read the response as JSON:

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

Calling `fetch()` returns a [promise](https://flaviocopes.com/javascript-promises/). The first callback receives a `Response`. The `json()` method reads its body and returns another Promise.

You can also use `await`:

```js
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](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#checking_response_status):

```js
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:

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

![Request headers for fetch](https://flaviocopes.com/images/fetch-api/request-headers.png)

#### status

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

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

#### statusText

[`statusText`](https://developer.mozilla.org/en-US/docs/Web/API/Response/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.

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

#### url

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

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

### Body content

A response has a body, accessible using several methods:

- `text()` returns the body as a string
- `json()` returns the body as a [JSON](https://flaviocopes.com/json/)-parsed object
- `blob()` returns the body as a [Blob](https://flaviocopes.com/blob/) object
- `formData()` returns the body as a FormData object
- `arrayBuffer()` returns the body as an [`ArrayBuffer`](https://flaviocopes.com/arraybuffer/) object

All those methods return a promise. Examples:

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

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

![Get JSON](https://flaviocopes.com/images/fetch-api/text-json.png)

The same can be written using an [async function](https://flaviocopes.com/javascript-async-await/):

```js
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:

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

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

- `method`: the request's method (GET, POST, etc.)
- `url`: the URL of the request
- `headers`: the associated Headers object of the request
- `referrer`: the referrer of the request
- `cache`: the cache mode of the request, such as `default`, `reload`, or `no-cache`

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:

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

or:

```js
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:

```js
fetch('./file.json')
```

we do

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

You can also query it:

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

and we can delete a header that was previously set:

```js
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:

```js
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`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).

Pass its signal to `fetch()`:

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

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

This cancels it after 5 seconds:

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

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

```js
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)
    }
  })
```
