Now that we’ve seen how XHR works, it’s time to see the “modern” version of it: the Fetch API.

Why modern? Because its primary benefit is that it uses promises as a building block, which means we can use async/await to make our code much better. It is also essential in combination with service workers to power Progressive Web Apps.

Fetch has a good support across the major browsers, except IE:

The browser support for the Fetch API

The polyfill https://github.com/github/fetch released by GitHub allows us to use fetch on any browser.

Using Fetch

Starting to use Fetch for GET requests is very simple:

const url = `file.json`
fetch(url)

and you’re already using Fetch: it’s going to make an HTTP request to get the file.json resource on the same domain.

Now let’s make this a bit more useful, let’s actually see what the content of the file is:

const response = await fetch(url)
const data = await response.json()
console.log(data)

This code must run in an async function:

(async () => {
  const response = await fetch(url)
  const data = await response.json()
  console.log(data)
})

Catching errors

We can use a try/catch block to intercept any error occurring during the execution of the request:

(async () => {
  try {
    const response = await fetch(url)
    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.

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

(async () => {
  try {
    const response = await fetch(url)
    console.log(response.headers.get('Content-Type'))
    console.log(response.headers.get('Date'))
  } catch(error) {
    console.error(error)
  }
})

The status property is an integer number representing the HTTP response status.

  • 101, 204, 205, or 304 is a null body status
  • 200 to 299, inclusive, is an OK status (success)
  • 301, 302, 303, 307, or 308 is a redirect
(async () => {
  try {
    const response = await fetch(url)
    console.log(response.status) //200
  } catch(error) {
    console.error(error)
  }
})

The statusText property represents the status message of the response. If the request is successful, the status is OK.

(async () => {
  try {
    const response = await fetch(url)
    console.log(response.statusText) //'OK'
  } catch(error) {
    console.error(error)
  }
})

The url property holds the full URL of the property that we fetched.

(async () => {
  try {
    const response = await fetch(url)
    console.log(response.url)
  } catch(error) {
    console.error(error)
  }
})

Body content

A response has a body, accessible using the text() or json() methods, which return a promise:

(async () => {
  try {
    const response = await fetch(url)
    const body = await response.text()
    console.log(body)
  } catch(error) {
    console.error(error)
  }
})
(async () => {
  try {
    const response = await fetch(url)
    const body = await response.json()
    console.log(body)
  } catch(error) {
    console.error(error)
  }
})

Get JSON

The 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 resource request details, including

  • 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 (e.g., default, reload, no-cache).

And exposes several methods including json(), text() and formData() to process the body of the request.

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

Set the request headers

Being able to set the HTTP request header is essential, and fetch gives us the ability to do this using the 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: app.post(‘/with-cors’, cors(), (req, res, next) => { res.json({msg: ‘Works! 🎉’}) })

const server = app.listen(3000, () => { console.log(“Listening on port %s”, server.address().port) })

fetch(url)

we do

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

fetch(request)

The Headers object is not limited to setting value, but we 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 allows to use any other HTTP method in your request: POST, PUT, DELETE or OPTIONS.

Specify the method in the method property of the request, and pass additional parameters in the header and in the request body:

Example of a POST request:

const options = {
  method: 'post',
  headers: {
    'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8'
  },
  body: 'foo=bar&test=1'
}

try {
  fetch(url, options)
} catch(err) {
  console.error('Request failed', err)
}

Video