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 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)
}
})
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 requestreferrer
: the referrer of the requestcache
: 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)
}