Javascript Fetch inside a map

Viewed 11287

I have a website/portfolio where I display all my projects using the Github API. My goal is to create a filter for these projects, so I created a file in the root of some repositories called "built-with.json", that file exists in only two repositories just for test purpose, that is a array of technologies I used in the project (example: ["React", "Javascript", ...]). So I need to fetch the Github APi(that part it's working well), then fetch that file, and return a new Array of projects but with an "filters" key where the value is the array inside of "built-with.json". Example:

Github API return (example of just one project returning):

[{
"id": 307774617,
"node_id": "MDEwOlJlcG9zaXRvcnkzMDc3NzQ2MTc=",
"name": "vanilla-javascript-utility-functions",
"full_name": "RodrigoWebDev/vanilla-javascript-utility-functions",
"private": false
}]

New array of objects that a I need:

[{
"id": 307774617,
"node_id": "MDEwOlJlcG9zaXRvcnkzMDc3NzQ2MTc=",
"name": "vanilla-javascript-utility-functions",
"full_name": "RodrigoWebDev/vanilla-javascript-utility-functions",
"private": false,
"filters": ["HTML5", "CSS3", "JS", "React"]
}]

This is what I did:

const url = "https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created";
fetch(url)
  .then((response) => response.json())
  .then((data) => {
      return data.map(item => {
        //item.full_name returns the repositorie name
        fetch(`https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`)
          .then(data => {
            item["filters"] = data
            return item
          })
      })
    })
  .then(data => console.log(data))

But it does not work! I get this in the console:

enter image description here

Someone can help me? Thanks in advance

Note: Sorry if you find some gramatical errors, my English it's a working in progress

3 Answers

A couple of things here. You don't need the .then() chained onto fetch(). fetch() returns a promise. Array.prototype.map() returns an array. Put together, you end up with an array of promises. You can resolve the array of promises with Promise.all(arrayOfPs)

EDIT: After your comments and reviewing your question, I've rewritten this so that it retrieves the skills from the filtered list of repositories.

const url = `https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created`;

(async() => {
  // Final results 
  let results;
  try {
    // Get all repositories
    const repos = await fetch(url).then((res) => res.json());
    const responses = await Promise.all(
      // Request file named 'build-with.json' from each repository
      repos.map((item) => {
        return fetch(
          `https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`
        );
      })
    );
    // Filter out all non-200 http response codes (essentially 404 errors)
    const filteredResponses = responses.filter((res) => res.status === 200);
    results = Promise.all(
      // Get the project name from the URL and skills from the file
      filteredResponses.map(async(fr) => {
        const project = fr.url.match(/(RodrigoWebDev)\/(\S+)(?=\/master)/)[2];
        const skills = await fr.json();
        return {
          project: project,
          skills: skills
        };
      })
    );
  } catch (err) {
    console.log("Error: ", err);
  }
  results.then((s) => console.log(s));
})();

The problem was that the fetch wasn't being returned hence the .map() was returning undefined. May I suggest a solution using async-await.

const url = "https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created";

getData(url).then(data => console.log(data));
  
async function getData(url){
  const response = await fetch(url);
  const data = await response.json();
  const arrOfPromises = data.map(item => fetch(`https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`)
  );
  return Promise.all(arrOfPromises);
}

You have multiple problems:

  1. Inside of map function you do not return any result
  2. Result of your map function will actually be another Promise (because of fetch inside).

So what you need to do:

  1. Return promise from map - as a result you will have array of promises
  2. Wait for all promises from point 1 using Promise.all

Something like this:



    var url1 = "https://api.github.com/users/RodrigoWebDev/repos?per_page=100&sort=created";
    var datum = fetch(url1)
      .then((response) => response.json())
      .then((data) => {
          return Promise.all(data.map(item => {
            //item.full_name returns the repositorie name
            return fetch(`https://raw.githubusercontent.com/${item.full_name}/master/built-with.json`)
              .then(data => {
                item["filters"] = data
                return item
              })
          }));
        }).then(data => console.log(data))

Related