# Getting Data with fetch

fetch sends a request to a web API and gives back a promise of the response; await it, then await response.json() to turn the JSON answer into a JavaScript value your page can use.

Apprentice · JavaScript · REST API · Web Development · Updated November 1, 2026

## After this lesson you can

- Load JSON from a web API with await fetch(url) and await response.json()
- Write an async function that builds an API address from a value and returns the data the page needs

## Key takeaways

- fetch(url) sends a GET request and gives back a promise. await fetch(url) waits for the response to arrive.
- A response has a status, an ok flag and headers straight away. Its body comes separately, and await response.json() reads it and turns the JSON into a JavaScript value.
- The body can be read only once, so read it into a variable and use the variable.
- Put a request in an async function that builds the URL with a template literal and returns only the data the page needs.

A movie site that shows tonight's showtimes, a music app that loads your playlists, a "random cat fact" button, a class project that has to show live data: each one is a page that asks an API for data and puts the answer on the screen. In JavaScript, the asking is one function, `fetch`, and it works the same in every browser and in Node.

In *What a Web API Is* you opened the Dog CEO API in your browser and read its JSON. This lesson gets the same data with code, so Riverbend Animal Shelter's breed explorer can show a dog photo the moment someone picks a breed.

## fetch: place the order, get a buzzer

At a busy restaurant, you place your order and they hand you a buzzer. The buzzer isn't your food; it's a promise that food is coming. When it buzzes, you collect the bag, and then you open it.

`fetch` (read "fetch", as in "go and get") works the same way. You give it a URL, it sends a `GET` request, and it hands you a **promise** right away: a value that stands for an answer that hasn't arrived yet (*Promises: then, catch and finally* explains promises in full). `await` (read "wait for this") pauses your code until the promise has an answer. Getting JSON takes two waits:

```javascript
const response = await fetch(url);
const data = await response.json();
```

1. **`await fetch(url)`** waits until the server starts answering. That's the bag handed through the window: you get a **response** object, with the status code and the headers, but not yet the food inside.
2. **`await response.json()`** waits for the rest of the answer, the **body**, to arrive, then reads its JSON and turns it into a JavaScript value. That's opening the bag.

`await` works inside an `async` function (*async and await*), and also at the top of a module file, outside any function. The examples here use the top of a module.

## Your first request

Here's a random beagle, fetched with code:

```javascript
const response = await fetch('https://dog.ceo/api/breed/beagle/images/random');
console.log(response.status);

const data = await response.json();
console.log(data);
```

```text
200
{
  message: 'https://images.dog.ceo/breeds/beagle/n02088364_852.jpg',
  status: 'success'
}
```

The status is `200`: it worked. `data` is now an ordinary JavaScript object, the same one you saw as JSON in the browser, so `data.message` is the photo's address. Run it again and you'll get a different beagle, because the API picks a photo at random.

**Try it.** In your course folder, make a folder named `dog-explorer`, with a `package.json` that holds `{ "type": "module" }`, as in *Modules: import and export*. Save the code above as `beagle.js` and run `node beagle.js` a few times. Copy one of the photo addresses into your browser to meet the dog. Then change `beagle` to `pug`.

## What's in a response

The response object arrives before its body, and it already tells you how the request went:

```javascript
const response = await fetch('https://dog.ceo/api/breed/beagle/images/random');

console.log(response.status);
console.log(response.statusText);
console.log(response.ok);
console.log(response.headers.get('content-type'));
```

```text
200
OK
true
application/json
```

- **`status`** is the status code, and **`statusText`** its name.
- **`ok`** is `true` when the status is in the 200s: it worked. *When fetch Fails* puts it to work.
- **`headers`** are labels on the answer. `content-type` says what kind of body it is: here, `application/json`, which is JSON.

The body can be read **only once**, the way you can only unpack a bag once. Call `response.json()` a second time and it fails with `TypeError: Body is unusable: Body has already been read` (Chrome says `body stream already read`). Read it once, into a variable, and use the variable.

## A function that builds the address

Real code doesn't fetch the same beagle every time. It puts the request in an `async` function, builds the URL from a value with a template literal (backticks with `${}`, read "dollar sign, curly braces"), and returns only what the page needs:

```javascript
async function randomPhotoOf(breed) {
  const response = await fetch(`https://dog.ceo/api/breed/${breed}/images/random`);
  const data = await response.json();
  return data.message;
}

const photo = await randomPhotoOf('husky');
console.log(photo);
```

```text
https://images.dog.ceo/breeds/husky/n02110185_1178.jpg
```

The rest of your program doesn't need to know about responses or JSON: it asks `randomPhotoOf('husky')` for a photo address and gets one. An `async` function always gives back a promise, so whoever calls it uses `await` too.

## Bigger answers: the breed list

Some answers are bigger than one address. The breed list's `message` is an object with a key per breed, and you dig into it the way you'd dig into any object:

```javascript
const response = await fetch('https://dog.ceo/api/breeds/list/all');
const data = await response.json();
const breeds = data.message;

console.log(Object.keys(breeds).length);
console.log(breeds.retriever);
console.log(`A ${breeds.retriever[3]} retriever`);
```

```text
108
[ 'chesapeake', 'curly', 'flatcoated', 'golden' ]
A golden retriever
```

`Object.keys` gives an array of an object's keys, so its length is the number of breeds the API knew on the day this lesson was written. An API's data changes over time, so your number may be different.

## On a page

In the browser, `fetch` is the same function. Here the shelter's page fetches a photo when someone clicks a button, and puts it in an `<img>`. The part of the page that matters:

```html
<button id="show-beagle">Show me a beagle</button>
<img id="dog-photo" alt="">
```

And `app.js`, loaded with `<script type="module" src="app.js">`:

```javascript
const button = document.querySelector('#show-beagle');
const photo = document.querySelector('#dog-photo');

button.addEventListener('click', async () => {
  const response = await fetch('https://dog.ceo/api/breed/beagle/images/random');
  const data = await response.json();
  photo.src = data.message;
  photo.alt = 'A random photo of a beagle';
});
```

The listener is an `async` arrow function, so it can `await`. Each click fetches a new beagle, and the page keeps working while the request is on its way: you can scroll and click the whole time.

**Try it.** Put the two blocks in `index.html` and `app.js` in your `dog-explorer` folder, with the page shape from *The HTML You Need for JavaScript*, and open it with Live Preview. A page opened straight from its file (an address starting `file://`) can't load modules, so always use Live Preview.

![The shelter's test page: a "Show me a beagle" button above a photo of a beagle sitting in the grass, which changes to a different beagle on every click](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/10/fd4391c680a04a109410d34990224c0b.webp)

## Check yourself

2 questions to try on the lesson page.

## So what

Two awaits, `fetch` and `response.json()`, are how a page gets live data from anywhere on the internet: dog photos today, weather, scores or your own app's server tomorrow.

## Key terms

- [Fetch API](https://www.ask-codey.com/glossary/fetch-api)
- [Response Object](https://www.ask-codey.com/glossary/response-object)
- [await](https://www.ask-codey.com/glossary/await)
- [async Function](https://www.ask-codey.com/glossary/async-function)
- [Template Literal](https://www.ask-codey.com/glossary/template-literal)

## Cheat sheets

- [Getting Data with fetch](https://www.ask-codey.com/cheat-sheets/javascript-fetch-getting-data-cheat-sheet)

## Related

- [What a Web API Is](https://www.ask-codey.com/lessons/javascript-web-apis-what-is-an-api)
- [async and await](https://www.ask-codey.com/lessons/javascript-promises-async-and-await)
- [When fetch Fails](https://www.ask-codey.com/lessons/javascript-fetch-when-it-fails)

Source: https://www.ask-codey.com/lessons/javascript-fetch-getting-data
