published: 03 Jul 2022
2 min read
How to use the Fetch API to make HTTP requests in JavaScript
The Fetch API is a promise-based JavaScript API for making asynchronous HTTP requests in the browser similar to XMLHttpRequest (XHR). Unlike XHR, it is a simple and clean API that uses promises to provide a more powerful and flexible feature set to fetch resources from the server.
Fetch API is pretty much standardized and is supported by all modern browsers except IE. If you need all browsers, including IE, just add a polyfill released by GitHub to your project.
Basic API Usage
Using Fetch API is really simple. Just pass the URL, the path to the resource you want to fetch, to the fetch()
method:
fetch('/js/users.json')
.then(response => {
// handle response data
})
.catch(err => {
// handle errors
})
We pass the path for the resource we want to retrieve as a parameter to fetch()
. It returns a promise that sends the response to then()
when it is fulfilled. The catch()
method intercepts errors if the request fails to complete due to network failure or other reasons.
GET Request
By default, the Fetch API uses the GET method for asynchronous requests. Let's use the Reqres REST API to retrieve a list of users using a GET request:
fetch('https://reqres.in/api/users')
.then(res => res.json())
.then(res => {
res.data.map(user => {
console.log('${user.id}: ${user.first_name} ${user.last_name}')
})
})
The above request prints the following on the console:
1: George Bluth
2: Janet Weaver
3: Emma Wong
Calling fetch()
method returns a promise. The response returned by the promise is a stream object. When we call the json()
method on the stream object, it returns another promise. Call to json()
method indicates that we are expecting a JSON response. For an XML response, you should use the text()
method.
POST Request
Just like Axios, Fetch also allows us to use any other HTTP method in the request: POST, PUT, DELETE, HEAD, and OPTIONS. All you need to do is set the method
and body
parameters in the fetch()
options:
const user = {
first_name: 'John',
last_name: 'Lilly',
job_title: 'Software Engineer'
}
const options = {
method: 'POST',
body: JSON.stringify(user),
headers: {
'Content-Type': 'application/json'
}
}
fetch('https://reqres.in/api/users', options)
.then(res => res.json())
.then(res => console.log(res))
The Reqres API returns the body data back with an ID and created timestamp attached:
{
'first_name':'John',
'last_name':'Lilly',
'job_title':'Software Engineer',
'id':'482',
'createdAt':'2019-05-12T15:09:13.140Z'
}
DELETE Request
The DELETE request looks very similar to the POST request, except body
is not required:
const options = {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
fetch('https://reqres.in/api/users/2', options)
.then(res => {
if (res.ok) {
return Promise.resolve('User deleted.')
} else {
return Promise.reject('An error occurred.')
}
})
.then(res => console.log(res))
Error Handling
Since the fetch()
method returns a promise, error handling is easy. We can use the catch()
method of the promise object to intercept any error thrown during the execution of the request.
However, no error will be thrown if the request hits the server and comes back, regardless of the server's response. The promise returned by fetch()
does not reject HTTP errors, even if the HTTP response code is 404 or 500.
Fortunately, you can use the ok
property of the response object to check whether the request was successful or not:
fetch('https://reqres.in/api/users/22') // 404 Error
.then(res => {
if (res.ok) {
return res.json()
} else {
return Promise.reject(res.status)
}
})
.then(res => console.log(res))
.catch(err => console.log('Error with message: ${err}'))
Request Headers
Request headers (like Accept
, Content-Type
, User-Agent
, Referer
, etc.) are essential for any HTTP request. The Fetch API's Headers
object allows us to set, remove, or retrieve HTTP request headers.
We can create a header object using the Headers()
constructor and then use the append
, has
, get
, set
, and delete
methods to modify request headers:
// create an empty 'Headers' object
const headers = new Headers()
// add headers
headers.append('Content-Type', 'text/plain')
headers.append('Accept', 'application/json')
// add custom headers
headers.append('X-AT-Platform', 'Desktop')
headers.append('X-AT-Source', 'Google Search')
// check if the header exists
headers.has('Accept') // true
// get headers
headers.get('Accept') // application/json
headers.get('X-AT-Source') // Google Search
// update header value
headers.set('Content-Type', 'application/json')
// remove headers
headers.delete('Content-Type')
headers.delete('X-AT-Platform')
We can also pass an array of arrays or an object literal to the constructor to create a header object:
// passing an object literal
const headers = new Headers({
'Content-Type': 'application/json',
Accept: 'application/json'
})
// OR
// passing an array of arrays
const headers = new Headers([
['Content-Type', 'application/json'],
['Accept', 'application/json']
])
To add headers to the request, simply create a Request
instance, and pass it to the fetch()
method instead of the URL:
const request = new Request('https://reqres.in/api/users', {
headers: headers
})
fetch(request)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err))
Request Object
The Request
object represents a resource request and can be created by calling the Request()
constructor:
const request = new Request('https://reqres.in/api/users')
The Request
object also accepts a URL object:
const url = new URL('https://reqres.in/api/users')
const request = new Request(url)
By passing a Request
object to fetch()
, you can easily customize the request properties:
method
- HTTP method likeGET
,POST
,PUT
,DELETE
,HEAD
url
- The URL to the request, a string or a URL objectheaders
- aHeaders
object for request headersreferrer
- referrer of the request (e.g.,client
)mode
- The mode for cross-origin requests (e.g.,cors
,no-cors
,same-origin
)credentials
- Should cookies and HTTP-Authorization headers go with the request? (e.g.,include
,omit
,same-origin
)redirect
- The redirect mode of the request (e.g.,follow
,error
,manual
)integrity
- The subresource integrity value of the requestcache
- The cache mode of the request (e.g,default
,reload
,no-cache
)
Let us create a Request
object with some customized properties and body content to make a POST request:
const user = {
first_name: 'John',
last_name: 'Lilly',
job_title: 'Software Engineer'
}
const headers = new Headers({
'Content-Type': 'application/json',
Accept: 'application/json'
})
const request = new Request('https://reqres.in/api/users', {
method: 'POST',
headers: headers,
redirect: 'follow',
mode: 'cors',
body: JSON.stringify(user)
})
fetch(request)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err))
Only the first argument, the URL, is required. All these properties are read-only. You can not change their value once the request object is created. The Fetch API does not strictly require a Request
object. The object literal, which we pass to the fetch()
method, acts like a Request
object:
fetch('https://reqres.in/api/users', {
method: 'POST',
headers: headers,
redirect: 'follow',
mode: 'cors',
body: JSON.stringify(user)
})
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err))
Response Object
The Response
object returned by the fetch()
method contains the information about the request and the response of the network request, including headers, status code, and status message:
fetch('https://reqres.in/api/users').then(res => {
// get response headers
console.log(res.headers.get('content-type))
console.log(res.headers.get('expires'))
// HTTP response status code
console.log(res.status)
// shorthand for 'status' between 200 and 299
console.log(res.ok)
// status message of the response e.g. 'OK'
console.log(res.statusText)
// check if there was a redirect
console.log(res.redirected)
// get the response type (e.g., 'basic', 'cors')
console.log(res.type)
// the full path of the resource
console.log(res.url)
})
The response body is accessible through the following methods:
json()
returns the body as a JSON objecttext()
returns the body as a stringblob()
returns the body as a Blob objectformData()
returns the body as a FormData objectarrayBuffer()
returns the body as an ArrayBuffer object
All these methods return a promise. Here is an example of text()
method:
fetch('https://reqres.in/api/unknown/2')
.then(res => res.text())
.then(res => console.log(res))
The output of the above network call will be a JSON string:
'{'data':{'id':2,'name':'fuchsia rose','year':2001,'color':'#C74375','pantone_value':'17-2031'}}'
Fetch & Cookies
When you use Fetch to get a resource, the request does not contain credentials such as cookies. If you want to send cookies, you have to explicitly enable credentials like the below:
fetch(url, {
credentials: 'include'
})
Fetch & Async/Await
Since Fetch is a promise-based API, we can go one step further and use the latest ES2017 async/await syntax to make our code even simpler and synchronous-looking:
const fetchUsers = async () => {
try {
const res = await fetch('https://reqres.in/api/users')
if (!res.ok) {
throw new Error(res.status)
}
const data = await res.json()
console.log(data)
} catch (error) {
console.log(error)
}
}
fetchUsers()
Conclusion
That's all folks for introduction to JavaScript Fetch API. It is a significant improvement over XMLHttpRequest
with a simple, elegant, and easy-to-use interface. Fetch works great for fetching network resources (even across the network inside the service workers).
The Fetch API is supported by all modern browsers, so there is no need to use any polyfill unless you want to support IE.
Read next: How to make HTTP requests using XHR in JavaScript.
Are we missing something? Help us improve this article. Reach out to us.
How to use the Fetch API to make HTTP requests in JavaScript
The Fetch API is a promise-based JavaScript API for making asynchronous HTTP requests in the browser similar to XMLHttpRequest (XHR). Unlike XHR, it is a simple and clean API that uses promises to provide a more powerful and flexible feature set to fetch resources from the server.
Fetch API is pretty much standardized and is supported by all modern browsers except IE. If you need all browsers, including IE, just add a polyfill released by GitHub to your project.
Basic API Usage
Using Fetch API is really simple. Just pass the URL, the path to the resource you want to fetch, to the fetch()
method:
fetch('/js/users.json')
.then(response => {
// handle response data
})
.catch(err => {
// handle errors
})
We pass the path for the resource we want to retrieve as a parameter to fetch()
. It returns a promise that sends the response to then()
when it is fulfilled. The catch()
method intercepts errors if the request fails to complete due to network failure or other reasons.
GET Request
By default, the Fetch API uses the GET method for asynchronous requests. Let's use the Reqres REST API to retrieve a list of users using a GET request:
fetch('https://reqres.in/api/users')
.then(res => res.json())
.then(res => {
res.data.map(user => {
console.log('${user.id}: ${user.first_name} ${user.last_name}')
})
})
The above request prints the following on the console:
1: George Bluth
2: Janet Weaver
3: Emma Wong
Calling fetch()
method returns a promise. The response returned by the promise is a stream object. When we call the json()
method on the stream object, it returns another promise. Call to json()
method indicates that we are expecting a JSON response. For an XML response, you should use the text()
method.
POST Request
Just like Axios, Fetch also allows us to use any other HTTP method in the request: POST, PUT, DELETE, HEAD, and OPTIONS. All you need to do is set the method
and body
parameters in the fetch()
options:
const user = {
first_name: 'John',
last_name: 'Lilly',
job_title: 'Software Engineer'
}
const options = {
method: 'POST',
body: JSON.stringify(user),
headers: {
'Content-Type': 'application/json'
}
}
fetch('https://reqres.in/api/users', options)
.then(res => res.json())
.then(res => console.log(res))
The Reqres API returns the body data back with an ID and created timestamp attached:
{
'first_name':'John',
'last_name':'Lilly',
'job_title':'Software Engineer',
'id':'482',
'createdAt':'2019-05-12T15:09:13.140Z'
}
DELETE Request
The DELETE request looks very similar to the POST request, except body
is not required:
const options = {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
fetch('https://reqres.in/api/users/2', options)
.then(res => {
if (res.ok) {
return Promise.resolve('User deleted.')
} else {
return Promise.reject('An error occurred.')
}
})
.then(res => console.log(res))
Error Handling
Since the fetch()
method returns a promise, error handling is easy. We can use the catch()
method of the promise object to intercept any error thrown during the execution of the request.
However, no error will be thrown if the request hits the server and comes back, regardless of the server's response. The promise returned by fetch()
does not reject HTTP errors, even if the HTTP response code is 404 or 500.
Fortunately, you can use the ok
property of the response object to check whether the request was successful or not:
fetch('https://reqres.in/api/users/22') // 404 Error
.then(res => {
if (res.ok) {
return res.json()
} else {
return Promise.reject(res.status)
}
})
.then(res => console.log(res))
.catch(err => console.log('Error with message: ${err}'))
Request Headers
Request headers (like Accept
, Content-Type
, User-Agent
, Referer
, etc.) are essential for any HTTP request. The Fetch API's Headers
object allows us to set, remove, or retrieve HTTP request headers.
We can create a header object using the Headers()
constructor and then use the append
, has
, get
, set
, and delete
methods to modify request headers:
// create an empty 'Headers' object
const headers = new Headers()
// add headers
headers.append('Content-Type', 'text/plain')
headers.append('Accept', 'application/json')
// add custom headers
headers.append('X-AT-Platform', 'Desktop')
headers.append('X-AT-Source', 'Google Search')
// check if the header exists
headers.has('Accept') // true
// get headers
headers.get('Accept') // application/json
headers.get('X-AT-Source') // Google Search
// update header value
headers.set('Content-Type', 'application/json')
// remove headers
headers.delete('Content-Type')
headers.delete('X-AT-Platform')
We can also pass an array of arrays or an object literal to the constructor to create a header object:
// passing an object literal
const headers = new Headers({
'Content-Type': 'application/json',
Accept: 'application/json'
})
// OR
// passing an array of arrays
const headers = new Headers([
['Content-Type', 'application/json'],
['Accept', 'application/json']
])
To add headers to the request, simply create a Request
instance, and pass it to the fetch()
method instead of the URL:
const request = new Request('https://reqres.in/api/users', {
headers: headers
})
fetch(request)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err))
Request Object
The Request
object represents a resource request and can be created by calling the Request()
constructor:
const request = new Request('https://reqres.in/api/users')
The Request
object also accepts a URL object:
const url = new URL('https://reqres.in/api/users')
const request = new Request(url)
By passing a Request
object to fetch()
, you can easily customize the request properties:
method
- HTTP method likeGET
,POST
,PUT
,DELETE
,HEAD
url
- The URL to the request, a string or a URL objectheaders
- aHeaders
object for request headersreferrer
- referrer of the request (e.g.,client
)mode
- The mode for cross-origin requests (e.g.,cors
,no-cors
,same-origin
)credentials
- Should cookies and HTTP-Authorization headers go with the request? (e.g.,include
,omit
,same-origin
)redirect
- The redirect mode of the request (e.g.,follow
,error
,manual
)integrity
- The subresource integrity value of the requestcache
- The cache mode of the request (e.g,default
,reload
,no-cache
)
Let us create a Request
object with some customized properties and body content to make a POST request:
const user = {
first_name: 'John',
last_name: 'Lilly',
job_title: 'Software Engineer'
}
const headers = new Headers({
'Content-Type': 'application/json',
Accept: 'application/json'
})
const request = new Request('https://reqres.in/api/users', {
method: 'POST',
headers: headers,
redirect: 'follow',
mode: 'cors',
body: JSON.stringify(user)
})
fetch(request)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err))
Only the first argument, the URL, is required. All these properties are read-only. You can not change their value once the request object is created. The Fetch API does not strictly require a Request
object. The object literal, which we pass to the fetch()
method, acts like a Request
object:
fetch('https://reqres.in/api/users', {
method: 'POST',
headers: headers,
redirect: 'follow',
mode: 'cors',
body: JSON.stringify(user)
})
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err))
Response Object
The Response
object returned by the fetch()
method contains the information about the request and the response of the network request, including headers, status code, and status message:
fetch('https://reqres.in/api/users').then(res => {
// get response headers
console.log(res.headers.get('content-type))
console.log(res.headers.get('expires'))
// HTTP response status code
console.log(res.status)
// shorthand for 'status' between 200 and 299
console.log(res.ok)
// status message of the response e.g. 'OK'
console.log(res.statusText)
// check if there was a redirect
console.log(res.redirected)
// get the response type (e.g., 'basic', 'cors')
console.log(res.type)
// the full path of the resource
console.log(res.url)
})
The response body is accessible through the following methods:
json()
returns the body as a JSON objecttext()
returns the body as a stringblob()
returns the body as a Blob objectformData()
returns the body as a FormData objectarrayBuffer()
returns the body as an ArrayBuffer object
All these methods return a promise. Here is an example of text()
method:
fetch('https://reqres.in/api/unknown/2')
.then(res => res.text())
.then(res => console.log(res))
The output of the above network call will be a JSON string:
'{'data':{'id':2,'name':'fuchsia rose','year':2001,'color':'#C74375','pantone_value':'17-2031'}}'
Fetch & Cookies
When you use Fetch to get a resource, the request does not contain credentials such as cookies. If you want to send cookies, you have to explicitly enable credentials like the below:
fetch(url, {
credentials: 'include'
})
Fetch & Async/Await
Since Fetch is a promise-based API, we can go one step further and use the latest ES2017 async/await syntax to make our code even simpler and synchronous-looking:
const fetchUsers = async () => {
try {
const res = await fetch('https://reqres.in/api/users')
if (!res.ok) {
throw new Error(res.status)
}
const data = await res.json()
console.log(data)
} catch (error) {
console.log(error)
}
}
fetchUsers()
Conclusion
That's all folks for introduction to JavaScript Fetch API. It is a significant improvement over XMLHttpRequest
with a simple, elegant, and easy-to-use interface. Fetch works great for fetching network resources (even across the network inside the service workers).
The Fetch API is supported by all modern browsers, so there is no need to use any polyfill unless you want to support IE.
Read next: How to make HTTP requests using XHR in JavaScript.
Are you looking for other code tips?
JS Nooby
Javascript connoisseur