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)
})
Result:
{
"message": [
"afghan",
"basset",
"blood",
"english",
"ibizan",
"plott",
"walker"
],
"status": "success"
}
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"}"
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()
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)
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:
response.blob()
response.formData()
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
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:
- The requested resource could not be found
- The URL is not recognized
- The endpoint is recognized but the resource is gone or missing
- 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>
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)
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>
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)
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)