The Fetch API
Connor Dillon
Posted on July 31, 2020
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).
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).
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 fromfetch()
won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (withok
status set tofalse
), 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()
Thefetch()
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
Basic Structure
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 theBody
reference for more.
Additional Uses for Fetch API
- Sending a request with credentials included
- Uploading JSON Data
- Uploading Multiple Files
- Checking if a Fetch was Successful
- 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:
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 withXHR
.
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
Posted on July 31, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.