JavaScript Resources: Async/Await + Fetch API
The fetch() function, the async keyword, and the await keyword are commonly used together when JavaScript needs to talk to a web API. These tools are important because they let you request data from a server, send data to a server, and then use the response in your program.
1. HTTP Methods and REST
When JavaScript communicates with a server, it usually sends an HTTP request to a URL. In a REST-style API, the URL usually names a resource, and the HTTP method tells the server what kind of action you want to perform.
Common HTTP Methods
| Method | Typical job | Example |
|---|---|---|
GET |
retrieve data | get all posts |
POST |
create data | create a new bookmark |
PATCH |
update part of a resource | change a caption |
DELETE |
remove a resource | delete bookmark 42 |
Example resource URLs
/api/posts
/api/bookmarks
/api/bookmarks/42
These URLs are noun-based. They describe the resource rather than the action.
2. What fetch() Returns
The fetch() function starts an HTTP request and immediately returns a Promise.
const promise = fetch('/api/posts');
console.log(promise);
That Promise will eventually resolve to a Response object.
const response = await fetch('/api/posts');
console.log(response);
Important distinction:
const response = await fetch('/api/posts');
const data = await response.json();
responseis theResponseobject from the serverdatais the parsed JavaScript value from the response body
3. async and await
The async keyword is used when you want to write a function that can use await.
async function loadPosts() {
const response = await fetch('/api/posts');
const data = await response.json();
console.log(data);
}
What async does
- allows you to use
awaitinside the function - makes the function return a Promise
What await does
- pauses the
asyncfunction until a Promise finishes - gives you the resolved value of that Promise
For example:
async function getMessage() {
const result = await Promise.resolve('hello');
console.log(result);
}
Without await, you would usually get a Promise instead of the final value.
4. Basic GET Request
If you want to retrieve data from an API, GET is the most common method:
async function loadPosts() {
const response = await fetch('/api/posts');
const posts = await response.json();
console.log(posts);
}
Typical workflow
- call
fetch(...) - wait for the response
- parse the JSON
- use the data
Here is a slightly larger example:
async function loadPosts() {
const response = await fetch('/api/posts');
const posts = await response.json();
const html = posts
.map(post => `<li>${post.caption}</li>`)
.join('');
document.querySelector('#results').innerHTML = html;
}
5. Sending JSON with POST
When you send JSON to a server, there are usually two important steps:
- convert the JavaScript object into JSON text using
JSON.stringify(...) - set the
Content-Typeheader toapplication/json
async function createPost(caption) {
const postData = { caption: caption };
const response = await fetch('/api/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(postData)
});
const data = await response.json();
return data;
}
If you forget JSON.stringify(...), you are not actually sending proper JSON.
6. Bearer Tokens and Protected Requests
Some endpoints require authentication. In those cases, you usually include a bearer token in the Authorization header.
headers: {
'Authorization': `Bearer ${token}`
}
Here is an example of a protected POST request:
async function createBookmark(postId, token) {
const response = await fetch('/api/bookmarks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ post_id: postId })
});
const data = await response.json();
return data;
}
And here is an example of a protected DELETE request:
async function deleteBookmark(bookmarkId, token) {
const response = await fetch(`/api/bookmarks/${bookmarkId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
const data = await response.json();
return data;
}
7. Common Mistakes
Mistake 1: forgetting await response.json()
async function loadPosts() {
const response = await fetch('/api/posts');
const data = response.json();
console.log(data);
}
Problem: response.json() also returns a Promise.
Fix:
async function loadPosts() {
const response = await fetch('/api/posts');
const data = await response.json();
console.log(data);
}
Mistake 2: sending a plain object as the body
await fetch('/api/posts', {
method: 'POST',
body: { caption: 'Hello' }
});
Fix:
await fetch('/api/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ caption: 'Hello' })
});
Mistake 3: forgetting Bearer
headers: {
'Authorization': token
}
Fix:
headers: {
'Authorization': `Bearer ${token}`
}
8. Practice Exercises
Exercise 1: Load JSON data
Write an async function called loadComments that fetches /api/comments, parses the JSON, and logs the result.
// Your code here
Show Answer
async function loadComments() {
const response = await fetch('/api/comments');
const data = await response.json();
console.log(data);
}
Exercise 2: Send JSON with POST
Write an async function called createComment(text) that sends { text: text } to /api/comments as JSON.
// Your code here
Show Answer
async function createComment(text) {
const response = await fetch('/api/comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ text: text })
});
return await response.json();
}
Exercise 3: Protected request
Write an async function called loadBookmarks(token) that fetches /api/bookmarks and includes the bearer token in the request headers.
// Your code here
Show Answer
async function loadBookmarks(token) {
const response = await fetch('/api/bookmarks', {
headers: {
'Authorization': `Bearer ${token}`
}
});
return await response.json();
}
Key Takeaways
fetch()returns a Promiseasynclets you useawaitawait fetch(...)gives you aResponseawait response.json()gives you the parsed data- when sending JSON, use
JSON.stringify(...)andContent-Type: application/json - protected endpoints often require
Authorization: Bearer ${token}