JS Async + Fetch
---
theme: seriph
title: "JS Async + Fetch"
info: "Module F-JS-005 — fetch, await, JSON, request/response shape, basic error handling with try/catch"
---
# JS Async + Fetch
---
layout: center
---
# What Is an API?
---
# API = Application Programming Interface
**A way for programs to talk to each other**
Think of it like a restaurant:
- **Menu** (API Documentation) -- shows what you can order
- **Waiter** (API) -- takes your request, brings back food
- **Kitchen** (Server) -- prepares what you ordered
You don't need to know how the kitchen works!
---
# How APIs Work
```
Your Website API Server
| |
|--- Request: "towns?" --->|
| |
|<-- Response: [{...}] ----|
| |
```
1. You **request** data from a URL
2. Server **processes** the request
3. Server **responds** with data (usually JSON)
---
layout: center
---
# JSON: The Language of APIs
---
# What Is JSON?
**JSON** = JavaScript Object Notation. A text format for structured data.
```json
{
"name": "Alice",
"age": 20,
"courses": ["OIM3690", "OIM3640"],
"active": true
}
```
- Keys must be in **double quotes**
- Values can be: strings, numbers, booleans, arrays, objects, `null`
- Looks like JavaScript objects, works everywhere
---
# Nested JSON
APIs often return objects inside arrays inside objects:
```json
{
"name": "Massachusetts",
"data": [
{
"name": "Boston",
"county": "Suffolk",
"population": 675647
},
{
"name": "Worcester",
"county": "Worcester",
"population": 206518
}
]
}
```
You navigate with dot notation and loops: `data.data[0].name`
---
layout: center
---
# What Does "Async" Mean?
---
# Synchronous vs Asynchronous
**Synchronous** -- each step waits for the previous one to finish:
```
Make coffee [====]
Toast bread [====]
Eat breakfast [====]
```
**Asynchronous** -- start tasks and handle them when they're ready:
```
Make coffee [====]
Toast bread [====]
Eat breakfast [====]
```
Fetching data from a server takes time (network delay). JavaScript doesn't freeze the page while waiting -- it works **asynchronously**.
---
# Why We Need `await`
`fetch()` does not give you data immediately. It gives you a **Promise**, a placeholder for data that has not arrived yet:
```js
const response = fetch('https://oim.zhili.dev/words/random');
console.log(response);
// Promise { <pending> } -- NOT the data!
```
The server needs time to respond. `await` tells JavaScript: **"wait here until the data arrives."**
> AI tip: If AI gives you fetch code without `await`, the data will be a Promise object instead of real data. Always check for `await`.
---
# Two `await` Calls
Every fetch needs two `await` steps:
```js
const response = await fetch('https://oim.zhili.dev/words/random');
const word = await response.json();
console.log(word); // "walked" -- actual data!
```
Two `await` calls:
1. `await fetch(...)` -- wait for the server to respond
2. `await response.json()` -- wait for the body to be parsed as JSON
---
# `async` Functions
`await` can only be used inside an `async` function:
```js
async function getRandomWord() {
const response = await fetch('https://oim.zhili.dev/words/random');
const word = await response.json();
document.querySelector('#result').textContent = word;
}
getRandomWord();
```
- **`async`** before function -- marks it as asynchronous
- **`await`** inside the function -- pauses until data arrives
> AI tip: Ask AI "write an async function that fetches data from [URL] and shows it on the page." It will generate the whole pattern for you.
---
# Your First `fetch()`
`fetch()` is built into every browser. Three steps:
```js
// 1. Fetch the URL
const response = await fetch('https://oim.zhili.dev/words/random');
// 2. Parse the JSON body
const word = await response.json();
// 3. Use the data
console.log(word);
```
**fetch** the URL, convert to **JSON**, **use** the data.
---
# The Response Object
`fetch()` returns a Response with useful properties:
```js
const response = await fetch('https://oim.zhili.dev/words/random');
console.log(response.status); // 200
console.log(response.ok); // true (status 200-299)
```
| Property | Meaning |
|---|---|
| `response.status` | HTTP status code (200, 404, 500) |
| `response.ok` | `true` if status is 200-299 |
| `response.json()` | Parse body as JSON (returns a Promise) |
---
# Working with Rich API Data
```js
async function showTowns() {
const response = await fetch('https://oim.zhili.dev/mass');
const data = await response.json();
console.log(data.name); // "Massachusetts"
console.log(data.governor); // "Maura Healey"
for (const town of data.data) {
console.log(`${town.name}: pop ${town.population}`);
}
}
```
Use dot notation to reach into nested JSON.
---
layout: center
---
# Error Handling with try/catch
---
# try/catch Pattern
API calls can fail (network down, bad URL, server error). Wrap `fetch` in `try/catch`:
```js
async function getRandomWord() {
try {
const response = await fetch('https://oim.zhili.dev/words/random');
const word = await response.json();
document.querySelector('#result').textContent = word;
} catch (error) {
document.querySelector('#result').textContent = 'Failed to load';
console.error('Error:', error);
}
}
```
- **`try`** -- run this code
- **`catch`** -- if anything throws an error, run this instead
> AI tip: If your fetch code works sometimes but fails other times, ask AI: "Add try/catch error handling to this fetch call."
---
layout: center
---
# Live Demo: OIM Teaching API
---
# Try It: Random Word
Open your browser console (`F12`) and paste:
```js
const response = await fetch('https://oim.zhili.dev/words/random');
const word = await response.json();
console.log(word);
```
Run it a few times -- you get a different word each time!
Note: `await` works at the top level in the console. In a `.js` file, always wrap it in an `async function`.
API docs: [oim.zhili.dev/docs](https://oim.zhili.dev/docs)
---
# Displaying API Data on the Page
```js
async function showTowns() {
const response = await fetch('https://oim.zhili.dev/mass');
const data = await response.json();
const list = document.querySelector('#town-list');
for (const town of data.data.slice(0, 10)) {
const li = document.createElement('li');
li.textContent =
`${town.name} (${town.county}) - pop ${town.population.toLocaleString()}`;
list.appendChild(li);
}
}
```
Same **loop + DOM** pattern from last session, now with real data!
---
# Pattern: Loading State
Show the user something is happening:
```js
async function loadData() {
const result = document.querySelector('#result');
result.textContent = 'Loading...';
try {
const response = await fetch('https://oim.zhili.dev/mass');
const data = await response.json();
result.textContent = `Found ${data.data.length} towns`;
} catch (error) {
result.textContent = 'Error loading data';
}
}
```
> AI tip: Ask AI "add a loading spinner to my fetch function" and it will generate the loading state pattern for you.
---
# Pattern: Search + Display
```js
async function findTown() {
const search = document.querySelector('#search').value.toLowerCase();
const response = await fetch('https://oim.zhili.dev/mass');
const data = await response.json();
const matches = [];
for (const town of data.data) {
if (town.name.toLowerCase().includes(search)) {
matches.push(town);
}
}
// Render the matches
const list = document.querySelector('#results');
list.innerHTML = '';
for (const town of matches) {
const li = document.createElement('li');
li.textContent = `${town.name} (${town.county})`;
list.appendChild(li);
}
}
```
---
# GET vs POST
```js
// GET: read/fetch data (default)
await fetch('https://oim.zhili.dev/words/random');
// POST: send/submit data
await fetch('https://oim.zhili.dev/message', {
method: 'POST',
body: JSON.stringify({ message: 'Hello from Alice!' })
});
```
- **GET** = "give me data" (reading)
- **POST** = "here's some data" (writing)
> AI tip: When you ask AI to connect to an API, tell it whether you need GET (reading data) or POST (sending data). This avoids confusion.
---
# Your Turn: Word Display
Create `js/word-fetch.js` linked from an HTML page with a button and a `<p id="result">`.
1. Write an `async function` that fetches a random word from `https://oim.zhili.dev/words/random`
2. Display the word in the `#result` paragraph
3. Add `try/catch` so the page shows "Failed to load" if the request fails
4. Wire the button's click event to call your function
> AI tip: Paste your HTML into AI and say "write a fetch function that loads a random word and displays it in #result." Compare its code to yours.
---
# Key Takeaways
1. APIs let your code **request data** from servers
2. `fetch()` makes HTTP requests; `await` waits for the response
3. Always parse the response with `.json()` before using it
4. Wrap every `fetch` in **`try/catch`** to handle errors
5. Use **loading states** so users know something is happening
---
# References
- [OIM Teaching API docs](https://oim.zhili.dev/docs)
- [MDN: Using Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
- [MDN: async/await](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await)
Topics Covered
- fetch
- await
- JSON
- request/response shape
- basic error handling with try/catch
Content Slides Open fullscreen ↗
Taught In
- Monday, 6/22 — JS async + fetch · API keys + .gitignore