Hello! Let's dive into our next lesson on asynchronous JavaScript.
Introduction
In our last lesson, you mastered how to use try...catch to handle errors within async/await functions. This gives you a robust pattern for writing resilient code that can deal with unexpected issues.
Today, we'll put that pattern to practical use. The learning outcome is to use the Fetch API with async/await to make GET and POST requests to a server. The Fetch API is the modern, built-in tool in browsers for communicating with servers. This skill is the cornerstone of building any web application that interacts with a backend, which is a key part of your goal to connect a React front-end to your Laravel applications.
We'll cover how to retrieve data from an API (a GET request) and how to send data to an API (a POST request), all using the clean async/await syntax you're now familiar with.
The Anatomy of a fetch Call
The fetch() function starts the process of fetching a resource from the network, and it returns a Promise. This is why it works so well with async/await.
A common point of confusion is that a typical fetch call involves two await keywords. Let's look at why.
The reason we "wait twice" is because fetch is a two-step process:
-
await fetch(url): The firstawaitpauses your function until the browser receives the initial response from the server. This response includes the HTTP headers and status code, but not the actual data (the response body). The promise resolves with aResponseobject. This object has useful properties likeresponse.status(e.g.,200,404) andresponse.ok(a boolean that istruefor statuses in the 200-299 range). -
await response.json(): The response body arrives as a "stream" of data. To read this stream to completion and parse it as a JSON object, we use the.json()method on theResponseobject. Since reading the stream can take time, this method also returns a Promise. The secondawaitpauses your function until the entire body has been downloaded and parsed.
Making GET Requests with async/await
A GET request is used to retrieve data from a server. It's the default method used by fetch.
Let's watch a video that refactors a fetch call from the older .then() syntax to the modern async/await syntax we're focusing on. This will clearly illustrate the benefits.
Fetch API with Async/Await (GET, POST, PUT, DELETE)
The following clip from ByteGrad demonstrates how to convert a standard GET request using fetch to the much cleaner async/await style. Pay attention to how the sequence of operations becomes more linear and easier to read.
Watch the segment from 06:14 to 08:45. Notice how await fetch(...) replaces the first .then() and await response.json() replaces the second one.
As the video shows, the code becomes much more intuitive. Now, let's incorporate the error handling you learned in the last lesson.
async function getUsers() {
const url = 'https://reqres.in/api/users';
try {
// Step 1: Start the request and wait for the response headers
const response = await fetch(url);
// Check if the request was successful (status 200-299)
// This is crucial for handling server errors like 404 (Not Found)
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// Step 2: Read the response body and parse it as JSON
const data = await response.json();
// Now you can work with the data
console.log('Users:', data.data);
return data.data;
} catch (error) {
// This will catch network errors (e.g., no internet connection)
// and the error we manually threw above.
console.error('Could not fetch users:', error);
}
}
getUsers();
This structure is the complete, modern pattern for making a GET request. All the asynchronous logic and error handling is contained neatly within one async function.
Making POST Requests: Sending Data to a Server
While GET requests are for retrieving data, POST requests are for sending data to a server, like submitting a form or creating a new resource.
To make a POST request with fetch, you need to provide a second argument: an options object that configures the request. The key properties for a POST request are:
method: The HTTP method, e.g.,'POST'.headers: An object specifying the request headers. To send JSON, you must include'Content-Type': 'application/json'.body: The data you want to send. It must be converted to a JSON string usingJSON.stringify().
Since you have experience with Laravel, this should feel familiar. You're essentially constructing the client-side version of the HTTP requests your Laravel routes consume.
This next video segment builds on the previous example to show how to configure a POST request.
Fetch API with Async/Await (GET, POST, PUT, DELETE)
Now, let's see how to send data. This clip from the same ByteGrad video explains how to configure the fetch options for a POST request.
Watch the segment from 11:01 to 13:20. Focus on the three key parts added to the fetch call: method, headers, and body.
Here is a complete example of a function that creates a new user by sending data via a POST request.
async function createUser(userData) {
const url = 'https://reqres.in/api/users';
try {
const response = await fetch(url, {
// 1. Specify the method
method: 'POST',
// 2. Set the headers to indicate you're sending JSON
headers: {
'Content-Type': 'application/json'
},
// 3. Provide the data, stringified into JSON format
body: JSON.stringify(userData)
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// The server often responds with the created object, including its new ID
const result = await response.json();
console.log('User created:', result);
return result;
} catch (error) {
console.error('Could not create user:', error);
}
}
// Example usage:
const newUser = {
name: 'Alex',
job: 'Laravel Developer'
};
createUser(newUser);
For a detailed textual reference on the different options you can use with fetch, the following article is an excellent resource.
Fetch - The Modern JavaScript Tutorial
This article from The Modern JavaScript Tutorial provides a comprehensive overview of fetch. I recommend reading the section on POST requests to solidify your understanding of the configuration options.
Read the section titled POST requests. It provides another clear example and reinforces the concepts of method, headers, and body.
Conclusion
You have now learned how to use fetch with async/await to perform the two most common types of API interactions: GET and POST. This is a fundamental skill for building the full-stack applications you're aiming for.
Key Takeaways:
fetch()is a modern, Promise-based API for making network requests.- Making a request and reading the body are two separate asynchronous steps, which is why we use two
awaitkeywords. - For GET requests, you just need the URL. For POST requests, you must provide an
optionsobject specifying themethod,headers(Content-Type), and thebody(as a JSON string). - Always check the
response.okproperty to handle server-side errors (like 404 or 500) gracefully inside yourtryblock. - The
try...catchblock is the perfect way to handle both network errors and server errors in a single, clean structure.
Preview of Next Lesson:
In our current examples, we've been waiting for one API call to finish before starting the next. But what if you need to fetch multiple pieces of data at the same time? In the next lesson, we will explore how to use Promise.all() to handle multiple concurrent asynchronous operations efficiently, making your applications faster and more responsive.