Fetching Data from the Dictionary API

Our dictionary app looks up words using the Free Dictionary API. Let’s walk through the code that handles searching, extracting data, and responding to errors.

Calling the API with fetch

The API base URL is stored in a constant. When the user clicks “Define”, we append their word to build the full URL:

const dictionaryAPI = "https://api.dictionaryapi.dev/api/v2/entries/en_US/";

const searchWord = async (word) => {
  const response = await fetch(`${dictionaryAPI}${word}`);
  if (!response.ok) {
    throw new Error(`Word not found (status ${response.status})`);
  }
  return response.json();
};

The API returns a 404 status when a word does not exist. Without this check, we would pass the error body along as if it were valid data. By throwing an error, we let the caller decide what to do. In our case, we show a message to the user.

Extracting Data from the Response

The API returns an array where the first element contains both meanings and phonetics. Rather than writing two nearly identical functions to pull these out, we use a single helper that takes the key we need:

const extractFromEntry = (data, key) => {
  if (data && Array.isArray(data)) {
    return data[0][key];
  }
};

Later in the code, this gets called as extractFromEntry(data, "meanings") and extractFromEntry(data, "phonetics").

The Click Handler

The event listener on the “Define” button handles the click. It reads the input, calls the API, and passes the results to display functions (which we explore in the next two sections):

submitBtn.addEventListener("click", async () => {
  const word = inputWord.value.trim();
  if (!word) return;

  try {
    const data = await searchWord(word);
    const meanings = extractFromEntry(data, "meanings");
    displayWordDefinition(meanings);
    const phonetics = extractFromEntry(data, "phonetics");
    displayWordPhonetic(phonetics);
  } catch (error) {
    displayError("Could not find the word. Please try another.");
  }
});

Since searchWord is async, the handler is async too. That lets us use await directly instead of chaining .then() calls.

Showing Errors in the UI

When something goes wrong (bad word, network issue), the catch block calls displayError, which clears the definitions section and shows a red message:

const displayError = (message) => {
  const definitionsSection = clearDefinitionsSection();
  const error = document.createElement("p");
  error.classList.add("p-4", "text-red-600", "font-semibold");
  error.innerText = message;
  definitionsSection.appendChild(error);
};

This way the user sees that something went wrong, instead of the failure showing up only in the console.