# Using Fetch API to make HTTP requests in JavaScript

By Atta Ur Rehman Shah (https://attacomsian.com/about). Published May 12, 2019, updated Jun 10, 2023. Topics: JavaScript.
Canonical URL: https://attacomsian.com/blog/javascript-fetch-api

> Learn what is JavaScript Fetch API, how it works, how to use it to request network resources with custom request headers, request and object objects, and more.

The Fetch API is a JavaScript API for making asynchronous HTTP requests in the browser, similar to XMLHttpRequest (XHR). It provides a promise-based and clean interface for fetching resources from a server.

The Fetch API is widely supported by modern browsers, except for Internet Explorer (IE). If you require IE support, you can include a [polyfill](https://github.com/github/fetch).

## Using the Fetch API

Using the Fetch API is straightforward. Simply pass the URL or path to the resource you want to fetch to the `fetch()` method:

```javascript
fetch('/js/users.json')
  .then(response => {
    // handle the response data
  })
  .catch(error => {
    // handle errors
  })
```

The `fetch()` method returns a [promise](https://attacomsian.com/blog/promises-javascript) that resolves to the response object when the request is fulfilled. You can use the `then()` method to handle the response data and the `catch()` method to handle errors.

## Making a GET request

By default, the Fetch API uses the GET method for asynchronous requests. Here's an example of retrieving a list of users from the Reqres REST API using a GET request:

```javascript
fetch('https://reqres.in/api/users')
  .then(response => response.json())
  .then(data => {
    data.data.forEach(user => {
      console.log(`${user.id}: ${user.first_name} ${user.last_name}`)
    })
  })
```

The above code fetches the list of users and logs their information to the console.

## Making a POST request

The Fetch API allows you to use various HTTP methods, including POST, PUT, DELETE, HEAD, and OPTIONS. To make a POST request, you need to set the `method` and `body` parameters in the `fetch()` options:

```javascript
const user = {
  first_name: 'John',
  last_name: 'Doe',
  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(response => response.json())
  .then(data => console.log(data))
```

In the above example, we send a POST request to create a new user and log the response data.

## Making a DELETE request

A DELETE request is similar to a POST request, but the `body` parameter is not required:

```javascript
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))
```

In this example, a DELETE request is made to delete a user with the ID 2. The response is checked, and a corresponding message is logged.

## Handling errors

Error handling with the Fetch API is straightforward. You can use the `catch()` method to intercept any errors thrown during the request execution. However, it's important to note that the Fetch API doesn't reject HTTP errors by default. To handle HTTP errors, you can check the `ok` property of the response object:

```javascript
fetch('https://reqres.in/api/users/22')
  .then(response => {
    if (response.ok) {
      return response.json()
    } else {
      throw new Error('Request failed with status ' + response.status)
    }
  })
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error))
```

In the above example, if the response is not successful (HTTP status code outside the range of 200-299), an error is thrown and caught in the `catch()` block.

## Customizing request headers

The Fetch API allows you to set, remove, or retrieve HTTP request headers using the `Headers` object. You can create a `Headers` object and use its methods to modify request headers:

```javascript
// 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')
```

You can pass an object literal or an array of arrays to the `Headers` constructor to create a header object. Here's an example:

```javascript
// 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']
])
```

In both cases, the `headers` object will contain the specified headers.

To include these headers in the request, you can create a `Request` instance and pass it to the `fetch()` method. Here's an example:

```javascript
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))
```

In this example, the `Request` object is created with the `headers` option set to the `headers` object we created earlier. Then, the `Request` object is passed as the first argument to the `fetch()` method. This ensures that the specified headers are included in the request.

By using the `Request` object, you have more control over the request and can customize various aspects, including headers, method, body, and more.

## Sending cookies

To send cookies with a Fetch request, you can enable credentials by including the `credentials: 'include'` option in the request configuration. Here's an example:

```javascript
fetch(url, {
  credentials: 'include'
})
```

By setting `credentials` to `'include'`, the request will include any cookies associated with the requested domain.

## Using async-await

The usage of `async/await` with Fetch is indeed a powerful combination that allows you to write asynchronous code in a more synchronous-like manner. The following example demonstrates how to use `async/await` with Fetch to simplify the code and handle errors gracefully.

```javascript
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()
```

By marking the function as `async` and using `await` before the Fetch call and `res.json()`, the code waits for the promises to resolve and behaves in a more synchronous manner.

## Conclusion

In conclusion, the Fetch API provides a modern and convenient way to make HTTP requests in JavaScript, and the combination of enabling credentials and using `async/await` can enhance the functionality and readability of your code.

If you're interested in learning about making HTTP requests using the older `XMLHttpRequest` object, you can refer to [this article](https://attacomsian.com/blog/http-requests-xhr).
