Fetching fallback url if the first url fails - javascript

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)
});
}

Related

fetch api objects storing inside an array problems

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();

Callback with recursive functions

I am using the google translate api to translate data from a json file to french locale and then write it back to a file. I am using a recursive function to iterate over the json file since it is deeply nested. However the execution is not waiting till the translation is completed before it writes to the file. I have tried using callback and promise approaches but i couldn't get it right.
Just for it to work as I required an output as an emergency I have set a timout before the write method is called. It work but I would like to learn the appropriate/correct approach to implement this.
const fs = require('fs')
const {Translate} = require('#google-cloud/translate').v2
require('dotenv').config()
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
const credentials = JSON.parse(process.env.credentials)
const translate = new Translate({
credentials,
projectId: credentials.project_id,
})
let data = {}
// writeJSONTofile should be executed only after readJSONFile execution is completed
//read file
const readJSONFile = () => {
try {
data = JSON.parse(fs.readFileSync('...\\locale\\en.json'))
iterateAndTranslate(data)
setTimeout(() => {
writeJSONToFile()
}, 25000)
} catch (error) {
console.log(error)
}
}
// iterate, translate, reassign
const iterateAndTranslate = async (data) => {
for(key in data) {
if (typeof data[key] === 'object' && data[key] !== null) {
iterateAndTranslate(data[key])
} else{
data[key] = await translateText(data[key], 'fr')
}
}
}
//translate method
const translateText = async (text, targetLanguage) => {
try {
let [response] = await translate.translate(text, targetLanguage)
return response
} catch (error) {
console.log(error)
return 0
}
}
const writeJSONToFile = async () => {
var outputFileName = 'C:\\test\\test.json'
await fs.writeFileSync(outputFileName, JSON.stringify(data,null,4), (err) => {
if(err) {
console.log(err)
} else {
console.log('Done!')
}
})
}
// start from here
readJSONFile()
You have a few issues with your code.
Your functions use a global variable and mutate it instead of getting input and returning output.
timeout will cause unexpected behavior in your case.
you are using var
you have redundant async-await on the writeJSONToFile function
See my view of point about the possible solution.
const fs = require("fs");
const { Translate } = require("#google-cloud/translate").v2;
require("dotenv").config();
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
const credentials = JSON.parse(process.env.credentials);
const translate = new Translate({
credentials,
projectId: credentials.project_id,
});
// writeJSONTofile should be executed only after readJSONFile execution is completed
//read file
const readJSONFile = async () => {
try {
const data = JSON.parse(fs.readFileSync("...\\locale\\en.json"));
return iterateAndTranslate(data);
} catch (error) {
console.log(error);
}
return {};
};
// iterate, translate, reassign
const iterateAndTranslate = async (data) => {
for (let key in data) {
if (typeof data[key] === "object" && data[key] !== null) {
await iterateAndTranslate(data[key]);
} else {
data[key] = await translateText(data[key], "fr");
}
}
return data;
};
//translate method
const translateText = async (text, targetLanguage) => {
try {
let [response] = await translate.translate(text, targetLanguage);
return response;
} catch (error) {
console.log(error);
}
return null;
};
const writeJSONToFile = (data) => {
let outputFileName = "C:\\test\\test.json";
fs.writeFileSync(outputFileName, JSON.stringify(data, null, 4), (err) => {
if (err) {
console.log(err);
} else {
console.log("Done!");
}
});
};
// start from here
const run = async () => {
const data = await readJSONFile();
writeJSONToFile(data);
};
run();
See more:
why not using global varible
why not using var

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;
})

Function with fetch returns undefined instead an array (React Native)

I have a file with some functions:
const API = {
async getComments() {
var data = [];
var url = 'http://url.com/wp-json/wp/v2/comments';
const serviceResponse = await fetch(
url,
)
.then((serviceResponse) => {
return serviceResponse.json();
} )
.catch((error) => console.warn("fetch error:", error))
.then((serviceResponse) => {
for (i in serviceResponse) {
data.push({
"key": serviceResponse[i]['id'].toString(),
"name": serviceResponse[i]['author_name'],
"content": serviceResponse[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": serviceResponse[i]['author_avatar_urls']['96'],
"date": serviceResponse[i]['date'].replace('T', ' ')
});
}
global.comments = data;
return data;
});
}
}
export { API as default }
In another file I include the file, and make the call:
var comments = await API.getComments(key);
console.log (comments);
But I receive undefined, I tried to create a function with bind:
this.newGetComments = API.getComments.bind(this); with the same result. I used a global variable, but I want to remove the globals vars.
/* Few suggestions;
1. you are not returning anything from the getComments method. Please return fetch(url) response.
2. you should return something from the catch block to handle the error.
*/
const API = {
async getComments() {
var url = 'http://url.com/wp-json/wp/v2/comments';
var response = await fetch(url)
.then(serviceResponse => {
return serviceResponse.json();
})
.then(serviceResponse => {
let data = [];
// rest of your code.
return { success: true, data };
})
.catch(error => {
console.warn('fetch error:', error);
return { success: false, error };
});
return response
},
};
var comments = await API.getComments(key);
if (comments.success) {
// handle the success case comments.data
} else {
// handle the Error case comments.error
}
console.log(comments);
An async function always returns a promise as you aren't returning anything from the getComments methods, the function automatically resolves and returns undefined(Promise.resolve(undefined)). You need to return serviceResponse from the getComments method to get the fetch api's response.
You can try something like below:
async componentDidMount() {
let data = [];
const result = await this.getComments();
const jsonData = await result.json();
console.log('Result ==> ', jsonData.serviceResponse);
jsonData.serviceResponse.map(data =>
data.push({
"key": data['id'].toString(),
"name": data[i]['author_name'],
"content": data[i]['content']['rendered'].replace(/<(.|\n)*?>/g, ''),
"gravatar": data[i]['author_avatar_urls']['96'],
"date": data[i]['date'].replace('T', ' ')
})
);
console.log('Data ==> ', data);
}
async getComments() {
const result = await fetch('http://url.com/wp-json/wp/v2/comments', {method: 'GET'});
return result;
}

Node.js handle responses from chained promises

I have 3 functions and each of them return a promise. How can I assign the response from each promise to a defined object?
This is my code:
const runResponse = {
webAudits: [],
webJourneys: [],
appJourneys: []
};
webAuditsFailures(req)
.then(
appJourneysFailures(req)
)
.then(
webJourneysFailures(req)
).then(
res.status(201).json({ reports: runResponse })
);
This is what I've tried:
webAuditsFailures(req)
.then(
(response) => {
runResponse.webAudits = response
},
appJourneysFailures(req)
)
.then(
(response) => {
runResponse.appJourneys = response
},
webJourneysFailures(req)
).then(
(response) => {
runResponse.webJourneys = response
},
res.status(201).json({ reports: runResponse })
);
But it doesn't works as expected because the webAuditsFailures is called again even if it didn't end and I don't understand why...
These are other failed attempts to fix this:
Using await
const webAudits = await webAuditsFailures(req);
const appJourneys = await appJourneysFailures(req);
const webJourneys = await webJourneysFailures(req);
runResponse.webAudits = webAudits;
runResponse.webJourneys = webJourneys;
runResponse.appJourneys = appJourneys;
The same thing happens with this:
const webAudits = await webAuditsFailures(req);
runResponse.webAudits = webAudits;
Using the co module:
co(function* () {
var runResponse = yield {
webAudits: webAuditsFailures(req),
webJourneys: appJourneysFailures(req),
appJourneys: webJourneysFailures(req)
};
res.status(201).json({ reports: runResponse });
});
Using Promise.all:
Promise.all([webAuditsFailures(req), appJourneysFailures(req),
webJourneysFailures(req)])
.then(function(allData) {
res.status(201).json({ reports: allData });
});
This is the webAuditsFailures function, which sequentially calls another functions that return a promise
export default async (req) => {
const report = req.body.webAudits;
const def = deferred();
if(report.length > 0) {
var reportList = [];
for(const [reportIndex, item] of report.entries()) {
for(const [runIndex, run] of item.runs.entries()) {
const result = await waComplianceBusiness(req, run.id);
var failureList = [];
if(result.data.overviews) {
const compliance = result.data.overviews[0].compliance;
if(compliance) {
for(const [index, rule] of compliance.entries()) {
const response = await waRuleOverview(req, run.id, rule.id);
const failedConditions = response.data.failedConditions;
const ruleName = response.data.ruleName;
if(response.data.pagesFailed > 0) {
for(const [condIndex, condition] of failedConditions.entries()) {
const request = {
itemId: condition.conditionResult.id,
itemType: condition.conditionResult.idType,
parentId: condition.conditionResult.parentId,
parentType: condition.conditionResult.parentType
}
const body = {
runId: run.id,
ruleId: rule.id,
payload: request
}
waConditionOverview(req, body).done(response => {
// do stuff here
});
}
}
}
if(failureList.length > 0) {
item.runs[runIndex].failures = failureList;
}
}
}
}
}
def.resolve(report);
return def.promise
}
else {
return [];
}
}
This is the problem:
waConditionOverview(req, body).done(response => {
// do stuff here
});
You're performing an async action but not waiting for the result. Don't use the deferred model - use util.promisify for callbacks.
In addition, I warmly recommend not mutating the request/resposne like this but storing the information in objects and returning those.
Here is how you'd write the code:
export default async (req) => {
const report = req.body.webAudits;
if(report.length === 0) return;
const runs = Array.from(report.entries(), ([i, item]) => item.runs.entries());
for (const [_, run] of runs) {
const result = await waComplianceBusiness(req, run.id);
var failureList = [];
if (!result.data.overviews) {
continue;
}
const compliance = result.data.overviews[0].compliance;
if(!compliance) {
continue;
}
for(const [_, rule] of compliance.entries()) {
const response = await waRuleOverview(req, run.id, rule.id);
const { failedConditions, ruleName} = response.data;
if(failureList.length > 0) {
item.runs[runIndex].failures = failureList;
}
if(response.data.pagesFailed === 0) continue;
for(const [_, condition] of failedConditions.entries()) {
const request = {
itemId: condition.conditionResult.id,
itemType: condition.conditionResult.idType,
parentId: condition.conditionResult.parentId,
parentType: condition.conditionResult.parentType
}
const body = { runId: run.id, ruleId: rule.id, payload: request}
const reponse = await waConditionOverview(req, body);
// do stuff here
// update response
// update report, so next time we try it's updated and doesn't return empty;
}
}
}
return report;
}
In a promise chain, the current .then() should return a promise. The result of this promise will be passed to the next .then():
webAuditsFailures(req)
.then((response) => {
runResponse.webAudits = response;
return appJourneysFailures(req); // return a promise
})
.then((response) => { // response contains the result of the promise
runResponse.appJourneys = response;
return webJourneysFailures(req);
})
.then((response) => {
runResponse.webJourneys = response;
res.status(201).json({ reports: runResponse });
});
Depending on what .json() in the last .then() does, you should return that as well if there are other .then()s in the promise chain.

Categories