Learning LibraryWebsite Development LibraryTeens

Fetching live data: ask an API, wait, show the answer

NASA publishes a new astronomy picture every day. Your page can show today's, without you ever editing it, by asking NASA's computers for the data when it loads.

The big idea

fetch requests data from a web address and await pauses until it arrives; an API is an address designed to answer with data instead of a page.

See it in code

1The basics

Three awaited steps: ask the address, turn the reply into an object with .json(), use the object's values. (This preview answers NASA's address with a small saved sample, so it runs anywhere.)

html
<section class="p-6">
  <h3 id="apod-title" class="text-xl font-bold"></h3>
  <p id="apod-date" class="text-sm text-violet-300"></p>
</section>
<script>
  async function loadApod() {
    const response = await fetch("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
    const data = await response.json();
    document.querySelector("#apod-title").textContent = data.title;
    document.querySelector("#apod-date").textContent = data.date;
  }

  loadApod();
</script>
A title and date that arrived as data:

A request takes time, so fetch returns immediately with a promise of a result. await waits for it, and is only allowed inside a function marked async.

2A step further

Data takes a moment to arrive, so show a loading state first. Any value in the reply can go on the page, including an image's src and alt:

html
<section class="mx-auto max-w-sm p-6">
  <p id="apod-status" class="text-slate-400">Contacting NASA...</p>
  <figure id="apod-card" class="hidden overflow-hidden rounded-2xl border border-white/10 bg-white/5">
    <img id="apod-image" src="" alt="" class="h-44 w-full object-cover">
    <figcaption class="space-y-2 p-5">
      <h3 id="apod-title" class="text-lg font-bold"></h3>
      <p id="apod-date" class="text-sm text-violet-300"></p>
      <p id="apod-text" class="text-sm text-slate-300"></p>
    </figcaption>
  </figure>
</section>
<script>
  async function loadApod() {
    const response = await fetch("https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
    const data = await response.json();
    document.querySelector("#apod-image").src = data.url;
    document.querySelector("#apod-image").alt = data.title;
    document.querySelector("#apod-title").textContent = data.title;
    document.querySelector("#apod-date").textContent = data.date;
    document.querySelector("#apod-text").textContent = data.explanation;
    document.querySelector("#apod-status").classList.add("hidden");
    document.querySelector("#apod-card").classList.remove("hidden");
  }

  loadApod();
</script>
A loading message, replaced when the data lands:

The card starts hidden and the status line visible. Only after the data has been placed do they swap, so a visitor never sees a half-filled card.

3On COSMOS

Requests fail: no connection, a typo in the address, a missing key. try and catch let the page say so gracefully. This request leaves out its API key on purpose:

html
<section class="p-6">
  <p id="apod-status" class="text-slate-400">Contacting NASA...</p>
  <h3 id="apod-title" class="text-xl font-bold"></h3>
</section>
<script>
  async function loadApod() {
    try {
      const response = await fetch("https://api.nasa.gov/planetary/apod");
      if (!response.ok) {
        throw new Error("NASA answered " + response.status);
      }
      const data = await response.json();
      document.querySelector("#apod-title").textContent = data.title;
      document.querySelector("#apod-status").classList.add("hidden");
    } catch (error) {
      document.querySelector("#apod-status").textContent = "Couldn't reach NASA right now. Please try again later.";
    }
  }

  loadApod();
</script>
A failed request, handled:

NASA refuses a request with no key and replies with status 403. response.ok is false, the code throws, and catch replaces the loading message with a helpful one.

The same idea, everywhere

Nearly every app you use is built this way. Weather, maps, messages, scores: a small program on your device asking a distant one for data, then drawing the answer.

Try it yourself

Add &date=2020-07-30 to the end of the working address to ask for a specific day, and show the date that comes back. Then remove one await and see what lands on the page.

The common mistake

Forgetting an await. Without it you're holding a promise, not the data, so data.title is undefined and the title comes out blank. Await anything that returns a promise.

What it unlocks

Fetched data is usually an array of objects, ready for building pages from data. It's placed on the page through the DOM, often in response to an event such as a button click.