Build an RPG Creature Search App Project - Build an RPG Creature Search App

i am trying very but still its not working can you please help me

I am helping. Just giving you the code to copy isn’t helpful.

I am not talking about clicking the automatic test button. Are you, the human at the computer, trying to repeat what the test is doing yourself?

yes i am working from past 2hours on this code

How did you manually test the test case with the search term ‘Red’?

Okay, thanks.
I just tried manually typing Red in the #search-input field and clicking the Search button, like you said.
It made a request to the API, and I checked the Network tab — it shows a 404 error, but my code isn’t showing the alert("Creature not found").
So I think my catch block isn’t running. I’ll try adding a console.log before and after the fetch to see what’s happening.

1 Like
searchButton.addEventListener("click", async () => {
  const query = searchInput.value.trim();
  console.log("Searching for:", query); // ✅ Debug

  try {
    const res = await fetch(
      `https://rpg-creature-api.freecodecamp.rocks/api/creature/${query.toLowerCase()}`
    );

    console.log("Response status:", res.status); // ✅ Debug

    if (!res.ok) {
      throw new Error("Creature not found");
    }

    const data = await res.json();
    console.log("Fetched data:", data); // ✅ Debug

    displayCreature(data);

  } catch (err) {
    console.error("Error caught:", err); // ✅ Debug
    alert("Creature not found");
    clearCreatureInfo();
  }
});

typed Red in the input and clicked Search.
I added console.log statements before and after the fetch call.
The Network tab shows a 404, and the console logs Response status: 404, but my code wasn’t going to the catch block before.
Now it does and shows the alert.

please help me I am still getting the error.

Please post your updated code.

/* file: script.js */
const input = document.getElementById("search-input");
const searchBtn = document.getElementById("search-button");
const allDiv = document.querySelectorAll("div");
const typeDiv = document.getElementById("types");

//urls
const dataUrl = "https://rpg-creature-api.freecodecamp.rocks/api/creatures";
const creatureUrl = "https://rpg-creature-api.freecodecamp.rocks/api/creature/";

async function getData() {
  try {
    const response = await fetch(dataUrl);
    const data = await response.json();
    return data;
  } catch (err) {
    console.error("Creature Arrary Fetch Error: ", err);
    return null;
  }
}

async function creatureStats(creature) {
  const url = creatureUrl + strParse(creature.id);
  console.log(url)
  try {
    const response = await fetch(url);
    const data = await response.json();
    return data;
  } catch (err) {
    console.error("Creature Stat Fetch Error: ", err);
  }
}

function getIdName(arr) {
  let hasName = false;
  arr.forEach(creature => {
    if (strParse(creature["name"]) === strParse(input.value) || strParse(creature["id"]) === strParse(input.value)) {
      hasName = true;
      return;
    }
  });
  if (hasName) {
    return strParse(input.value);
  } else {
    alert("Creature not found");
    return;
  }
}

function strParse(str) {
  return str.toString().trim().toLowerCase();
}

function getCreature(data, idName) {
  let creatureObj;
  data.forEach(monster => {
    if (strParse(monster.id) === idName || strParse(monster.name) === idName) {
      creatureObj = monster;
    }
  });
  return creatureObj;
}

function displayData(data) {
  allDiv.forEach(div => {
    switch (div["id"]) {
      case "creature-name":
        div.textContent = data["name"];
        break;
      case "creature-id":
        div.textContent = data["id"];
        break;
      case "weight":
        div.textContent = data["weight"];
        break;
      case "height":
        div.textContent = data["height"];
        break;
      case "types":
        const arr = [];
        let strArr = [];
        data["types"].forEach(type => {
          const text = type["name"].toUpperCase();
          arr.push(text);
        });
        arr.forEach(e => {
          strArr.push(`<div>${e}</div>`)
        });
        div.innerHTML = strArr.join("");
        break;
      case "hp":
        data["stats"].forEach(stat => {
          if (stat["name"] === "hp") {
            div.textContent = stat["base_stat"];
          }
        });
        break;
      case "attack":
        data["stats"].forEach(stat => {
          if (stat["name"] === "attack") {
            div.textContent = stat["base_stat"];
          }
        });
        break;
      case "defense":
        data["stats"].forEach(stat => {
          if (stat["name"] === "defense") {
            div.textContent = stat["base_stat"];
          }
        });
        break;
      case "special-attack":
        data["stats"].forEach(stat => {
          if (stat["name"] === "special-attack") {
            div.textContent = stat["base_stat"];
          }
        });
        break;
      case "special-defense":
        data["stats"].forEach(stat => {
          if (stat["name"] === "special-defense") {
            div.textContent = stat["base_stat"];
          }
        });
        break;
      case "speed":
        data["stats"].forEach(stat => {
          if (stat["name"] === "speed") {
            div.textContent = stat["base_stat"];
          }
        });
        break;
    }
  });
}

function search() {
  
  getData().then(dataArr => {
    let idName = getIdName(dataArr);
    if(idName) {
      let creatureObj = getCreature(dataArr, idName);
      creatureStats(creatureObj).then(data => {
        displayData(data);
      });
    }
  });
  typeDiv.innerHTML = "";
  
}

searchBtn.addEventListener("click", () => {
  search();
});

So why did you change the code in the searchButton event listener from what you last posted? All you had to do from there was change the name of updateUI to displayCreature and scrap some of the other code you no longer need. Then you just needed to deal with the errors in that updateUI function using console.log() to debug.

i change the code still its show the same error

/* file: script.js */
const input = document.getElementById("search-input");
const searchBtn = document.getElementById("search-button");
const allDiv = document.querySelectorAll("div");

// URLs
const dataUrl = "https://rpg-creature-api.freecodecamp.rocks/api/creatures";
const creatureUrl = "https://rpg-creature-api.freecodecamp.rocks/api/creature/";

// Fetch all creatures
async function getData() {
  try {
    const response = await fetch(dataUrl);
    const data = await response.json();
    return data;
  } catch (err) {
    console.error("Creature Array Fetch Error: ", err);
    return null;
  }
}

// Fetch single creature stats
async function creatureStats(creature) {
  const url = creatureUrl + strParse(creature.id);
  console.log("Fetching stats from:", url);
  try {
    const response = await fetch(url);
    const data = await response.json();
    return data;
  } catch (err) {
    console.error("Creature Stat Fetch Error: ", err);
  }
}

// Utility: lowercase/trim
function strParse(str) {
  return str.toString().trim().toLowerCase();
}

// Validate input exists in data
function getIdName(arr) {
  let hasName = false;
  arr.forEach(creature => {
    if (
      strParse(creature["name"]) === strParse(input.value) ||
      strParse(creature["id"]) === strParse(input.value)
    ) {
      hasName = true;
      return;
    }
  });
  if (hasName) {
    return strParse(input.value);
  } else {
    alert("Creature not found");
    return;
  }
}

// Get the creature object from the list
function getCreature(data, idName) {
  let creatureObj;
  data.forEach(monster => {
    if (strParse(monster.id) === idName || strParse(monster.name) === idName) {
      creatureObj = monster;
    }
  });
  return creatureObj;
}

// Display creature details
function displayCreature(data) {
  console.log("Creature data:", data); // ✅ debug
  allDiv.forEach(div => {
    switch (div.id) {
      case "creature-name":
        div.textContent = data.name;
        break;
      case "creature-id":
        div.textContent = data.id;
        break;
      case "weight":
        div.textContent = data.weight;
        break;
      case "height":
        div.textContent = data.height;
        break;
      case "types":
        const typeHTML = data.types
          .map(type => `<div>${type.name.toUpperCase()}</div>`)
          .join("");
        div.innerHTML = typeHTML;
        break;
      case "hp":
      case "attack":
      case "defense":
      case "special-attack":
      case "special-defense":
      case "speed":
        const stat = data.stats.find(s => s.name === div.id);
        div.textContent = stat ? stat.base_stat : "";
        break;
    }
  });
}

// Main search flow
function search() {
  getData().then(dataArr => {
    let idName = getIdName(dataArr);
    if (idName) {
      let creatureObj = getCreature(dataArr, idName);
      creatureStats(creatureObj).then(data => {
        displayCreature(data);
      });
    }
  });
}

// ✅ Event listener
searchBtn.addEventListener("click", search);

like this

Failed: 14. When the #search-input element contains the value Red and the #search-button element is clicked, an alert should appear with the text "Creature not found".
Failed: 15. When the #search-input element contains the value Pyrolynx and the #search-button element is clicked, the values in the #creature-name, #creature-id, #weight, #height, #hp, #attack, #defense, #special-attack, #special-defense, and #speed elements should be PYROLYNX, #1 or 1, Weight: 42 or 42, Height: 32 or 32, 65, 80, 50, 90, 55, and 100, respectively.
Failed: 16. When the #search-input element contains the value Pyrolynx and the #search-button element is clicked, a single element should be added within the #types element that contains the text FIRE. The #types element content should be cleared between searches.
Failed: 17. When the #search-input element contains the value 2 and the #search-button element is clicked, the values in the #creature-name, #creature-id, #weight, #height, #hp, #attack, #defense, #special-attack, #special-defense, and #speed elements should be AQUOROC, #2 or 2, Weight: 220 or 220, Height: 53 or 53, 85, 90, 120, 60, 70, and 40, respectively.
Failed: 18. When the #search-input element contains the value 2 and the #search-button element is clicked, two elements should be added within the #types element that contain text values WATER and ROCK, respectively. The #types element content should be cleared between searches.
Failed: 19. When the #search-input element contains an invalid creature name and the #search-button element is clicked, an alert should appear with the text "Creature not found".
Failed: 20. When the #search-input element contains a valid creature ID and the #search-button element is clicked, the UI should be filled with the correct data.

    Failed: 21. When the search button is clicked, the app should send a fetch request to the correct endpoint for the creature name or ID.

index.html

i am literally trying from yesterday please help me

I just did. You didn’t listen.

i dont understand please can you clarify to me

What is it you don’t understand about what I posted?

I understand what you meant — you were saying I didn’t need to rewrite the whole event listener. I should have just renamed the updateUI function to displayCreature and focused on fixing the errors inside it using console.log() for debugging. Thanks for clarifying — I see where I went off track.

but still its not running


when i type input it shows correct output.

But why test failed is showing

please anyone here know this :folded_hands: