The Fetch API
Tags: javascript, api, http, architecture
Published: 2020-07-31 02:35:25

<!-- TOC -->

- [Fetch API](#fetch-api)
    - [Concepts and Usage](#concepts-and-usage)
        - [Fetch vs. jQuery.ajax](#fetch-vs-jqueryajax)
    - [Fetch Interfaces](#fetch-interfaces)
    - [Fetch mixin](#fetch-mixin)
    - [Specifications](#specifications)
    - [Basic Structure](#basic-structure)
    - [Additional Uses for Fetch API](#additional-uses-for-fetch-api)
    - [Headers](#headers)
        - [Guard](#guard)
    - [Response Objects](#response-objects)
    - [Body](#body)
    - [References and Links](#references-and-links)

<!-- /TOC -->

> The **Fetch API** provides an **interface for fetching resources** (including across the network). It will seem **familiar to anyone who has used XMLHttpRequest**, but the new API **provides a more powerful and flexible feature set**.

## Concepts and Usage

The Fetch API provides a **JavaScript** interface for accessing and manipulating parts of the **HTTP pipeline**, such as **requests and responses**. Fetch also provides a generic definition of `Request` and `Response` objects.
It also provides a definition for related concepts such as **CORS** and the **HTTP** origin header semantics, supplanting their separate definitions elsewhere.

For making a request and fetching a resource, use the `WindowOrWorkerGlobalScope.fetch()` method. It is implemented in multiple interfaces, specifically `Window` and `WorkerGlobalScope`.

The `fetch()` method takes one mandatory argument, the path to the resource you want to fetch. It returns a `Promise` that resolves to the `Response` to that request, **whether it is successful or not**. _You can also optionally pass in an init options object as the second argument ([see Request here](https://developer.mozilla.org/en-US/docs/Web/API/Request))._

Once a `Response` is retrieved, there are a number of methods available to define what the `body` content is and how it should be handled ([see Body here](https://developer.mozilla.org/en-US/docs/Web/API/Body)).

### Fetch vs. `jQuery.ajax()`

Fetch's functionality was previously achieved using `XMLHttpRequest`. Fetch provides a better alternative that can be easily used by other technologies such as **Service Workers**.
Fetch differs in two main ways:

- The `Promise` returned from `fetch()` won’t reject on HTTP error status **even if the response is an HTTP 404 or 500**. Instead, it will resolve normally (with `ok` status set to `false`), and it will only reject on network failure or if anything prevented the request from completing.
- By default, `fetch` won't send or receive any cookies from the server, **resulting in unauthenticated requests if the site relies on maintaining a user session** (to send cookies, the credentials init option must be set).

## Fetch Interfaces

> **`WindowOrWorkerGlobalScope.fetch()`**
> The `fetch()` method used to fetch a resource.

> **`Headers`**
> Represents response/request headers, allowing you to query them and take different actions depending on the results.

> **`Request`**
> Represents a resource request.

> **`Response`**
> Represents the response to a request.

## Fetch mixin

> **`Body`**
> Provides methods relating to the body of the response/request, allowing you to declare what its content type is and how it should be handled.

## Specifications

> **[Fetch Living Standard](https://fetch.spec.whatwg.org/)**

## Basic Structure

```js
fetch('http://example.com/movies.json')
  .then(function (response) {
    return response.json()
  })
  .then(function (myJson) {
    console.log(JSON.stringify(myJson))
  })
```

Here we are fetching a _JSON_ file across the network and printing it to the console. The simplest use of `fetch()` takes one argument — the path to the resource you want to fetch — and **returns a promise** containing the response (a `Response` object).
This is just an **HTTP response, not the actual JSON**. To _extract the JSON body content from the response, we use the_ `json()` _method (defined on the_ `Body` _mixin, which is implemented by both the_ `Request` _and_ `Response` _objects.)_

> Note: The `Body` mixin also has similar methods to extract other types of body content; **see the `Body` reference for more.**

## Additional Uses for Fetch API

- [Sending a request with credentials included](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Sending_a_request_with_credentials_included)
- [Uploading JSON Data](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Uploading_JSON_data)
- [Uploading Multiple Files](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Uploading_multiple_files)
- [Checking if a Fetch was Successful](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful)
- [Supplying your own Request Object](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Supplying_your_own_request_object)

## Headers

The Headers interface allows you to create your own headers object via the Headers() constructor. A headers object is a simple multi-map of names to values:

```javascript
var content = 'Hello World'
var myHeaders = new Headers()
myHeaders.append('Content-Type', 'text/plain')
myHeaders.append('Content-Length', content.length.toString())
myHeaders.append('X-Custom-Header', 'ProcessThisImmediately')
```

The same can be achieved by passing an array of arrays or an object literal to the constructor.
The contents of `Headers` can be queried and retrieved.
Some of these operations are only useful in `ServiceWorkers`, but they provide a much nicer API for manipulating headers.

All of the `Headers` methods throw a `TypeError` **if a header name is used that is not a valid HTTP** `Header` **name**. The mutation operations will throw a `TypeError` if there is an immutable guard (see below). Otherwise they fail silently.
A good use case for headers is checking whether the **content type** is correct before you process it further.

### Guard

Since headers can be sent in requests and received in responses, and have various limitations about what information can and should be mutable, headers objects have a guard property. This is not exposed to the Web, but it affects which mutation operations are allowed on the headers object.

**Possible guard values are:**

> `none`: default.
> `request`: guard for a headers object obtained from a request (Request.headers).
> `request-no-cors`: guard for a headers object obtained from a request created with Request.mode no-cors.
> `response`: guard for a Headers obtained from a response (Response.headers).
> `immutable`: Mostly used for ServiceWorkers; renders a headers object read-only.

> Note: You may not append or set a `request` guarded Headers’ `Content-Length` header. Similarly, inserting `Set-Cookie into a response header is not allowed: ServiceWorkers are not allowed to set cookies via synthesized responses.

## Response Objects

As you have seen above, Response instances are returned when `fetch()` promises are resolved.

The most common response properties you'll use are:

`Response.status` — An integer (default value 200) containing the response status code.
`Response.statusText` — A string (default value "OK"), which corresponds to the HTTP status code message.
`Response.ok` — seen in use above, this is a shorthand for checking that status is in the range 200-299 inclusive. This returns a Boolean.

They can also be created programmatically via **JavaScript**, but this is only really useful in **ServiceWorkers**, when you are **providing a custom response to a received request using a** `respondWith()` **method:**

```javascript
var myBody = new Blob()

addEventListener('fetch', function (event) {
  // ServiceWorker intercepting a fetch
  event.respondWith(
    new Response(myBody, {
      headers: { 'Content-Type': 'text/plain' },
    })
  )
})
```

The `Response()` constructor takes two optional arguments — a **body** for the response, and an **init** object _(similar to the one that_ `Request()` _accepts.)_

> Note: The static method `error()` simply returns an error response. Similarly, `redirect()` returns a response resulting in a redirect to a specified URL. **These are also only relevant to Service Workers.**

## Body

Both requests and responses may contain body data. **A body is an instance of any of the following types:**

- `ArrayBuffer`
- `ArrayBufferView` (Uint8Array and friends)
- `Blob`/File
- string
- `URLSearchParams`
- `FormData`

The `Body` mixin defines the following methods to extract a body (implemented by both `Request` and `Response`). These all **return a promise** that is eventually **resolved with the actual content**.

- `arrayBuffer()`
- `blob()`
- `json()`
- `text()`
- `formData()`
  This makes usage of non-textual data much easier than it was with `XHR`.

Request bodies can be set by passing body parameters:

```javascript
var form = new FormData(document.getElementById('login-form'))
fetch('/login', {
  method: 'POST',
  body: form,
})
```

Both `request` and `response` (and by extension the `fetch()` function), **will try to intelligently determine the content type**. A request will also **automatically set a Content-Type header** if none is set in the dictionary.

## References and Links

- **[MDN: The Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)**
- **[MDN: Using Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)**
- **[MDN: Global Fetch](https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch)**
- **[MDN: Fetch API Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)**
- **[MDN: Fetch API Body](https://developer.mozilla.org/en-US/docs/Web/API/Body)**
- **[Living Standard: Fetch](https://fetch.spec.whatwg.org/)**