The more I look at javascript projects around the web the more I see that there is a lack understanding of the fetch api that is natively built into the browser. There were days where we used to rely on something like jQuery.ajax to make remote network calls. However in the modern browser fetch should be mostly natively supported. I still see a lot of people rely on libraries like axios, eventhough axios can be nice, why add a dependency to your app when you can just use the native fetch API built into the browser.

This post will be a 'cheatsheet' for those looking to natively use fetch.

GET JSON Data and Assign to Variable

Since fetch will return a Promise we need to make sure it is resolved before we can get the actual data. You can try this out in your browser's console.

// declare the empty object
let data = {}
fetch('https://api.github.com/repos/frontojs/connect')
  .then(function(response) { return response.json() })
  .then(function(body) { data = body })

data.id
<= 92484313

POST JSON Data to an Endpoint

Previously we used github's public api to make a GET request. You can use https://requestbin.com/ to create a url you can post data to. To make a POST request we can do the following.

let result = {}

const data = {
  message: {
    body: "This is a message"
  }
}

fetch('https://enpeshq1qgq0l.x.pipedream.net/', {
  method: 'POST',
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(data)
})
  .then(function(response) { return response.json() })
  .then(function(data) { result = data })
  
result
<= {success: true}
You should see something like this in your request bin

Here we can see that in the second argument we can pass in the options to modify our request. Essentially you are passing in the options to create the Request object which is a part of the fetch api https://developer.mozilla.org/en-US/docs/Web/API/Request. Here are a list of options you can pass in.

// the option with * is the default
{
  method: "POST", // *GET, POST, PUT, DELETE, etc.
  mode: "cors", // no-cors, cors, *same-origin
  cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
  credentials: "same-origin", // include, *same-origin, omit
  headers: {
    "Content-Type": "application/json",
    // "Content-Type": "application/x-www-form-urlencoded",
  },
  redirect: "follow", // manual, *follow, error
  referrer: "no-referrer", // no-referrer, *client,
  body: JSON.stringify(data)
}

Alot of times you will want to authenticate with your web application using the existing cookie. For example if you are using devise with your rails app you may need to let devise authenticate and return the cookie then you may want to make requests in your javascript code. You can use the same-origin option for credentials like so.

fetch('https://enpeshq1qgq0l.x.pipedream.net/', {
  method: 'POST',
  headers: {
    "Content-Type": "application/json"
  },
  credentials: "same-origin",
  body: JSON.stringify(data)
}).then(...)

Using Async/Await

Once you understand how fetch works it's very easy to make a simple wrapper with async/await to make using fetch a little easier. For example If you want to make a request and return the result without messing around with promises you can do something like this.

const get = async (url, callback) => {
  const response = await fetch(url)
  const status = await response.status
  
  if (callback) callback[status](await response.json())
}

With a function like this what you can essentially do is call get and pass the url and a callback like this.

let myData = {}

get('https://api.github.com/repos/frontojs/connect, {
  200: body => { myData = body }
})

myData.id
<= 92484313

This way you can handle the result based on the status returned. This is great if you need to handle errors etc... Imagine if you had an error 404 or 422 you can display the error to your user using the callbacks without having to mess around with promises or async / await.

If you prefer promises you can create something like this

const get = async (url) => {
  const response = await fetch(url)
  const status = await response.status

  if (status >= 200 && status < 300) {
    return await response.json()
  } else {
    // throw the object you desire which you will handle
    // in this case the json error response might give us
    // a json body so we can use that.
    throw { status: status, body: await response.json() }
    // or throw an error 
    // throw Error(await response.statusText)
  }
}

Essentially what this is doing is it will return you a json result if the response is successful for anything else simply throw an error. We can then use this api like this.

get('https://api.github.com/repos/frontojs/connect')
  .then(json => doSomething(json))
  .catch(error => handleError(error))

You should now have a general idea of how fetch works you can use this to craft your own SDK for your api which can be easy for the developer to use. So imagine having one function for each type of method.

request.get or request.post request.patch request.delete

If you would like to learn more about fetch in the context of a React application you can check out our free episodes

making-post-request-cover

You can also ask us any questions you have on our discussion forum.