DEV Community

Cover image for The Only Parts of Fetch API in JavaScript That Will Get You Far In Your Career
jsmanifest
jsmanifest

Posted on

The Only Parts of Fetch API in JavaScript That Will Get You Far In Your Career

The fetch api in JavaScript provides developers an interface to work with HTTP requests and the HTTP pipeline. It is also used to process responses received from those requests. Sending requests with the fetch api is working with asynchronous code using the global Promise object in JavaScript to deliver flexibly.

It is the successor to XMLHttpRequest which is a better (and modern) alternative to communicate with resources remotely across the network. It can perform all of the tasks that XMLHttpRequest was capable with.

I am a lead engineer and I spent 100% of my time on JavaScript. It is my only language I am comfortable with. I also spent too much time trying to master fetch in all of its ins and outs because in the real world you most likely won't be needing to use things like TextDecoder or any of that extra stuff to work with HTTP requests/responses. There is a good reason behind this: The weird parts are already done for you in libraries available publicly.

So what I learned over time when working on projects in general is that striving for perfection is not the solution to achieve success. There is no perfect solution. But a good way to get very far in life is to work smart.

In this post we will go over the parts of the fetch api that is just enough to get you very far in your development career. This means that you will rarely be using methods from the fetch api outside of this tutorial. In other words, the information in this article is just enough to get you to focus on other parts of your JavaScript development career. You don't need to understand everything about fetch in order to succeed. You just need the understand the parts you will be asked to do in your projects.

A chief officer in my company (who is specialized in a skill outside of I.T.) recently applauded for an employee member in another department that quickly spun up a website which performs very fast. That employee used wordpress. He worked smart.

Sending Requests and Receiving Responses

You should be familiar with the Request and Response object that the fetch object communicates with. When you work with these two objects you are actually hitting a lot of birds with one stone, because as you venture out in the real world you will notice that these two objects are either mimiced or reused in frameworks like Gatsby functions, the development server in webpack, native libraries in Node.js use this interface as well in their http module.

The properties/methods are also purposely used as a convention to work with responses in libraries like got, so by knowing Request and Response you will have sort of a "shortcut" in the learning process of open sourced tools.

The most common method you will be using from fetch is the get method.

The example below is making a get request to fetch a list of hound dog breeds:

window.addEventListener('load', async (event) => {
  const url = `https://dog.ceo/api/breed/hound/list`

  const response = await fetch(url)
  const result = await response.json()

  console.log(result)
})
Enter fullscreen mode Exit fullscreen mode

Result:

{
  "message": [
    "afghan",
    "basset",
    "blood",
    "english",
    "ibizan",
    "plott",
    "walker"
  ],
  "status": "success"
}
Enter fullscreen mode Exit fullscreen mode

The resource becomes available as a Response object after the request completes.

This Response object contains your data which is the most sensitive part, so it needs to be taken care of like it is your baby. fetch also provides different methods for working with the Response. It is the wrapper for the fetched resource that comes with useful properties and methods to inspect it.

The way we obtain the data depends on the methods we use and majority of the time it also depends on the type of the contents. We would resolve the response's contents using the JavaScript Promise API which helps us parse the contents into the final format we expect.

For example, when the response is returned and we want to obtain the data in the raw text format, the Response provides the .text() method to read the fetched resource's contents:

const result = await response.text()
// Result: "{"message":["afghan","basset","blood","english","ibizan","plott","walker"],"status":"success"}"
Enter fullscreen mode Exit fullscreen mode

In this example we used the text method and it was successfully resolved to us. This is fine but when we look at the contents it's actually a JSON string.

Since the data is already a JSON string, we can just use the json method to automatically parse the string into a javascript object for us (otherwise we would have to parse it ourselves every time by using JSON.parse):

const response = await fetch(url)
const result = await response.json()
Enter fullscreen mode Exit fullscreen mode

Most of the time especially in modern web development we'll mostly be using the .json() method to read data. But it's worth mentioning that we should be aware of when not to use it, or else we would end up with something like this:

const response = await fetch(url)
const result = await response.json()

console.log(result)
Enter fullscreen mode Exit fullscreen mode

fetch-in-javascript-json-method-error.png

This is a catastrophic error because it typically stops our application from behaving the way we expect it to afterwards.

There are other ways we can read the response data (which all comes in as a Promise) such as:

  1. response.blob()
  2. response.formData()
  3. response.arrayBuffer()

Response Status Codes

The Response object also comes with three properties we can use to inspect if the request succeeded or not:

const response = await fetch(url)

console.log(response.status) // 200
console.log(response.statusText) // "OK"
console.log(response.ok) // true
Enter fullscreen mode Exit fullscreen mode

The most important property here is the .status property. It returns an HTTP status code which identifies the status of the request's response which we can use to handle the upcoming steps for our app accordingly.

The most common (and necessary) status codes we should know is 404 and 500 (and 200 for success) due to its frequent occurrences on the web.

When responses return with a 404 status code it usually means one of:

  1. The requested resource could not be found
  2. The URL is not recognized
  3. The endpoint is recognized but the resource is gone or missing
  4. The request resource is protected from unauthorized users from viewing it

When responses return with a status code of something above 500 it is an error from the server itself. I commonly see 500 as opposed to its related codes like 503 which means that the server could not handle the error it received so the response was returned empty instead.

Fetch Use Cases

We can use the fetch in JavaScript browser environments to retrieve data (as shown previously), but we can also use it as a way to modify or add resources to a location.

For example, we can use it to process data after selecting to upload files in the DOM:

<form name="upload-form" method="post">
  <label for="upload-files">Click to upload one or more files</label>
  <input
    name="upload-files"
    type="file"
    placeholder="Select file(s)"
    multiple
  /><input />
</form>
Enter fullscreen mode Exit fullscreen mode

With this we can use fetch in our form submit handlers to upload files for our users:

async function onSubmit(event) {
  event.preventDefault()
  const fileInput = [...event.target.elements].find((el) => el.type === 'file')
  const filesList = fileInput.files
  const file = filesList[0]

  await fetch(`/upload-my-data?filename=${file.name}`, {
    body: file,
    method: 'post',
  })
}

document
  .querySelector(`form[name="upload-form"]`)
  .addEventListener('submit', onSubmit)
Enter fullscreen mode Exit fullscreen mode

We can also use it to upload data in JSON format to create plain object resources on a remote location:

<form name="new-profile-form" method="post">
    <div>
        <input type="text" name="name" placeholder="Your Name"></input>
    </div>
    <div>
        <input type="text" name="email" placeholder="Your Email"></input>
    </div>
    <div>
        <textarea name="message" placeholder="Message" ></textarea>
    </div>
    <button type="submit">Submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode
async function onSubmit(event) {
  event.preventDefault()
  const body = {}
  const formElements = [...this.elements].filter((el) =>
    el.hasAttribute('name'),
  )

  for (const el of formElements) {
    body[el.getAttribute('name')] = el.value
  }

  const response = await fetch(`/upload-my-data`, {
    body: JSON.stringify(body),
    method: 'post',
  })

  console.log(`[onSubmit] data`, await response.json())
}

document
  .querySelector(`form[name="new-profile-form"]`)
  .addEventListener('submit', onSubmit)
Enter fullscreen mode Exit fullscreen mode

fetch-post-json-data-javascript.png

Conclusion

These are the the base features you really need to get very far in your web development career. If there comes a time when asked to do something out of your scope that fetch is capable of doing, then all you have to do is google it.

And that concludes the end of this post! I found you found this to be valuable and look out for more in the future!

Find me on medium

Top comments (0)