fetch api objects storing inside an array problems - javascript

I am fetching pokemon's name and image using a nested fetch method. I have successfully
created pokemon objects. but I am unable to store them inside pokemonsArray. what I am doing wrong here? how can I store them inside an array what should be a good approach to do it please guide me?
const cards = document.querySelector(".cards");
const error = document.querySelector(".err");
const search = document.querySelector("#search");
let url = "https://pokeapi.co/api/v2/pokemon?limit=100&offset=0";
let pokemonsArray = [];
const createPokemons = (pokemon) => {
pokemonsArray.push(pokemon);
};
const getPokemon = () => {
fetch(url)
.then((res) => {
if (!res.ok) {
throw new Error("data could not be fetched");
} else {
return res.json();
}
})
.then((data) => {
const pokemonArray = data.results;
pokemonArray.map((pokemon) => {
fetch(pokemon.url)
.then((result) => {
if (!result.ok) {
throw new Error("could not fetch new url");
} else {
return result.json();
}
})
.then((data) => {
let pokemon = {
name: data.species.name,
image: data.sprites.other.home.front_default,
};
createPokemons(pokemon);
});
});
})
.catch((err) => {
console.log(err);
});
};
console.log(pokemonsArray.length); // 0 !!! why result is 0;
getPokemon();

Related

update two remote api and retry multiple time

My goal is to fetch data from two remote api and update the data from the two api simultaneously. If the first api update pass and the second api update fails, all update should be reverse. I am having issue in making sure all data is fetch and update at the same time. Please see my current code below. I am working in node.js environment. Thanks.
const remote1 = 'https://jsonplaceholder.typicode.com/posts/1'
const remote2 = 'https://jsonplaceholder.typicode.com/posts/2'
var data1;
var data2;
fetch(remote1)
.then(res => res.json())
.then(data => data1 = data)
fetch(remote1)
.then(res => res.json())
.then(data => data2 = data)
const trys= 3;
function updateApi() {
return new Promise((ok, fail) => {
setTimeout(() => data1.id = 2, data2.id = 3 ? ok("OK!") : fail("Error"), 6000);
});
}
async function Retry(updateApi, count = trys) {
if (count > 0) {
const result = await updateApi().catch(e => e);
if (result === "Error" ) {
return await Retry(updateApi, count - 1) }
return result
}
return `Tried ${trys} times and failed`;
}
Retry(updateApi).then(console.log);
Don't use promise as like callback, Promise is just future value,
const remote1 = 'https://jsonplaceholder.typicode.com/posts/1'
const remote2 = 'https://jsonplaceholder.typicode.com/posts/2'
var data1 = fetch(remote1)
.then(res => res.json())
.then(data => data1 = data)
var data2 = fetch(remote1)
.then(res => res.json())
.then(data => data2 = data)
function updateApi() {
// waiting for both `data1` and `data2` to resolve...
return Promise.all([data1, data2]).then(_ => {
data1.id = 2;
data2.id = 3;
})
}
async function Retry(updateApi, count = 3) {
if (!count) throw `Tried ${count} times and failed`
try {
await updateApi();
} catch (error) {
await Retry(updateApi, count - 1)
}
}
Retry(updateApi)
.then(() => console.log({ data1, data2 }))
.catch(console.log);

Problem accessing object property created using Promise

I am not able to access the returned object property, Please tell me why its returning undefined when data is object and giving correct value.
This is function created to sendHTTPRequest based on data.
import { countryCap } from "./capitalizingFunc.js";
export const sendHTTPRequest = (country) => {
const capitalisedCountry = countryCap(country);
return fetch(
`https://covid-19-coronavirus-statistics.p.rapidapi.com/v1/total?country=${capitalisedCountry}`,
{
method: "GET",
headers: {
"x-rapidapi-key": "3b0f2e00ebmsh95246403d9540c9p1506d4jsn3c44ce26f745",
"x-rapidapi-host": "covid-19-coronavirus-statistics.p.rapidapi.com",
},
}
)
.then((response) => {
const newResponce = response.json();
return newResponce;
})
.catch((err) => {
console.error(err);
});
};
This is constructor class
export class casesDataFetcher {
constructor(countryName) {
sendHTTPRequest(countryName)
.then((response) => {
return response.data;
})
.then((data) => {
this.country = data.location;
this.cases = data.confirmed;
this.recovered = data.recovered;
this.deaths = data.deaths;
console.log(this);
return this;
});
}
}
This is execution function
import { casesDataFetcher } from "./casesDataFetcher.js";
export const screenDataShower = (country) => {
const dataStorage = [];
const globalInfected = document.querySelector(".infected h2");
const globalActive = document.querySelector(".active h2");
const globalDeaths = document.querySelector(".deaths h2");
const globalRecovered = document.querySelector(".recovered h2");
const globalCountries = document.querySelector(".countries h2");
let promise = new Promise(function (resolve, reject) {
const recordedData = new casesDataFetcher(country);
console.log(recordedData);
resolve(recordedData);
});
return promise.then((data) => {
console.log(typeof data);
console.log(typeof data);
console.log(data.cases); // NOT WORKING GIVING UNDEFINED
globalInfected.textContent = `${nn.cases}`;
globalActive.textContent = data.cases - data.recovered - data.deaths;
globalDeaths.textContent = data.deaths;
globalRecovered.textContent = data.recovered;
globalCountries.textContent = 219;
});
};
I also tried to convert the data to JSON again but still I was not able to access the property of returned data in screenDataShower
you're calling sendHTTPRequest inside casesDataFetcher's constructor, from your code there's no guarantee data is resolved when you access it
extract sendHTTPRequest into a new function and wrap into a promise
export class casesDataFetcher {
constructor(countryName) {
this.countryName = countryName
}
fetch = () => {
return new Promise((res, rej) => {
sendHTTPRequest(this.countryName)
.then((response) => {
return response.data;
})
.then((data) => {
this.country = data.location;
this.cases = data.confirmed;
this.recovered = data.recovered;
this.deaths = data.deaths;
console.log(this);
res(this);
});
})
}
}
make screenDataShower function async then you can await data from fetch function in casesDataFetcher, this way it can guarantee data is there when you access it
import { casesDataFetcher } from "./casesDataFetcher.js";
export const screenDataShower = async (country) => {
const dataStorage = [];
const globalInfected = document.querySelector(".infected h2");
const globalActive = document.querySelector(".active h2");
const globalDeaths = document.querySelector(".deaths h2");
const globalRecovered = document.querySelector(".recovered h2");
const globalCountries = document.querySelector(".countries h2");
const _casesDataFetcher = new casesDataFetcher(country)
const data = await _casesDataFetcher.fetch()
console.log(typeof data);
console.log(typeof data);
console.log(data.cases); // NOT WORKING GIVING UNDEFINED
globalInfected.textContent = `${nn.cases}`;
globalActive.textContent = data.cases - data.recovered - data.deaths;
globalDeaths.textContent = data.deaths;
globalRecovered.textContent = data.recovered;
globalCountries.textContent = 219;
};
The problem is that the json method of your response returns a promise instead of plain JSON. So you should change the call of the json method in your sendHTTPRequest function to something like:
.then((response) => {
const newResponse = response.json().then((jsonResponse) => jsonResponse);
return newResponse;
})

Fetching fallback url if the first url fails

I have a function
getAllSymbolsConfig = async reels => {
const symbols = new Set();
for (const column of reels) {
for (const symbol of column.symbols) {
symbols.add(symbol);
}
}
const coords = {};
for (const symbol of symbols) {
const response = await fetch(
`${this.props.gameDir}icons/${symbol}.json`
);
const json = await response.json();
coords[symbol] =
json.frames.find(frame => frame.filename.includes("active_0000")) ||
json.frames.find(frame => frame.filename.includes("active")) ||
json.frames[0];
coords[symbol].meta = json.meta;
}
return coords;
};
where it tries to fetch data from url ${this.props.gameDir}icons/${symbol}.json
However, in some situations ${symbol} variable is not available and I need to replace it with hardcoded url icon.json:
${this.props.gameDir}icons/icon.json
How would i retry the second fallback url if the first one fails?
Updated Try this:
function fetchData(url) {
await fetch(url).then((response) => {
return response;
})
}
let response = null;
response = fetchData(`${this.props.gameDir}icons/${symbol}.json`)
if (response.status == 400 ) {
response = fetchData(hardCodedUrl)
}
if (!!response) {
response.then((returnedResponse) => {
// Your response to manipulate
}).catch((error) => {
// Your error is here!
console.log(error)
});
}

Cannot access object/array in Javascript

I can console.log and see the array I created but as soon as I attempt to access it, I get undefined.
async componentDidMount() {
// fetch goal data for display
let response = await fetchWithToken("http://localhost:8080/api/getGoals");
let goalData = await response.json();
goalData = await goalData.filter(skill => skill.Skill === "CS_en");
// get info from people API with distinct list rather than every row
let people = new Set([]);
goalData
.filter(element => element.UpdatedBy !== null)
.forEach(element => {
people.add(element.UpdatedBy);
});
people = Array.from(people);
// call peopleAPI
const peopleObj = await peopleAPI(people);
console.log("peopleObj :", peopleObj);
console.log("peopleObj[0] :", peopleObj[0]);
}
Here is the peopleAPI where I'm calling another api and getting a list of user info.
const peopleAPI = people => {
return new Promise(function(resolve, reject) {
// get people API info
const peopleObj = [];
const apiPromises = [];
if (people) {
people.forEach(empid => {
const apiPromise = fetch(
`https://someApiCall/${empid}`
)
.then(res => res.json())
.then(res => {
peopleObj.push({
empid: res.id,
name: res.name.preferred ? res.name.preferred : res.name.full
});
})
.then(() => apiPromises.push(apiPromise));
});
// once all promises have been resolved, return a promise with the peopleObj
Promise.all(apiPromises).then(() => {
resolve(peopleObj);
});
}
});
};
export default peopleAPI;
Results of console.logs
Don't use push inside fetch.then, just return its value, and then push it to apiPromises`
const peopleAPI = people => {`
return new Promise(function(resolve, reject) {
// get people API info
const apiPromises = [];
if (people) {
people.forEach(empid => {
const apiPromise = fetch(`https://someApiCall/${empid}`)
.then(res => res.json())
.then(res => {
return {
empid: res.id,
name: res.name.preferred ? res.name.preferred : res.name.full
}
});
apiPromises.push(apiPromise)
});
Promise.all(apiPromises).then((data) => {
resolve(data);
});
}
});
};
export default peopleAPI;
Or even simpler and readable
const peopleAPI = people => {`
const apiPromises = people.map(empid => {
return fetch(`https://someApiCall/${empid}`)
.then(res => res.json())
.then(res => ({
empid: res.id,
name: res.name.preferred ? res.name.preferred : res.name.full
}));
});
return Promise.all(apiPromises)
};

Refactoring how react/node handles response

I'm using a react frontend and fetching data from my node server. I feel like my code looks a bit redundant, is there a better way to refactor all this?
App.js
searchStock = async (value) => {
let priceURL = `/stock/${ value }/price`
// fetch price data
fetch(priceURL)
.then(res => {
if (res.ok) {
res.json()
.then( (result) => {
this.setState({
price: result
})
})
}
else {
console.log("Something went wrong...")
}
})
}
server.js
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetch(apiURL)
.then(response => {
console.log(response.status)
if (response.ok) {
response.json().then((data) => {
res.json(data)
});
}
else {
res.sendStatus(response.status)
}
})
.catch(error => {
console.log(error);
});
})
As these two code segments live in different apps (frontend and backend) I don't think there's a pretty way of DRYing this.
Introduce library file with fetching logic
src/helper.js
exports.fetchHelper = (url) => fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
res.sendStatus(response.status)
}
})
.catch(console.error);
and use respectively
app.js
import { fetchHelper } from 'src/helper'; // or whatever else your bundler setup requires
searchStock = async (value) => {
const priceURL = `/stock/${ value }/price`;
await fetchHelper(priceURL).then((result) => {
this.setState({
price: result
})
})
}
server.js
const fetchHelper = require('src/helper').fetchHelper;
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetchHelper(apiURL).then((response) => {
res.json(data);
})
Or something similar...

Categories