How to Fetch Data from Multiple API in one function? - javascript

Here is my codes:
const ids = [1,2,3,4,5,6,7,8,9,10];
const fD= () => {
const fP = ids?.map(async (id) => {
const { data } = await axios.get(`https://jsonplaceholder.typicode.com/posts/${id}/comments`);
return data;
})
return fP;
};
console.log(fD());
my following codes is not working to fetch data and get data same as i expected.
I am trying to fetch 10 API in one time to get the information and get them in one array. somethings like this: (suppose i fetch only id's from all API)
Expected Output:
[[{1},{2},{3},{4},{5}],[{6},{7},{8},{9},{10}],[{11},{12},{13},{14},{15}],[{16},{17},{18},{19},{20}],[{21},{22},{23},{24},{25}],[{26},{27},{28},{29},{30}],[{31},{32},{33},{34},{35}],[{36},{37},{38},{39},{40}],[{41},{42},{43},{44},{45}],]{46},{47},{48},{49},{50}]]
How Can i fetch multiple API in one time and get all the data in array?
Anyone can help me to fetch multiple API in one time and fetch those data same as i Expect.
Thankyou for Your helping in advance!

I think promise.all() will solve your problem. It takes an array of promises as input and returns a single promise that resolves to an array of results of input promises.
Helpful links:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Multiple API Calls with Promise.all

Related

In getServerSideProps, how to execute the return statement after all fetching is complete?

I have access to the username of a person and I can access their corresponding data object using one fetch from firebase. This data object has a lot of properties, including one which is called "uploads" which is an array of documentIDs where each id is that of a post uploaded by the user. I want to fetch all these documents, make it an array and return the ENTIRE array back to the page.
I have written this code so far: https://i.stack.imgur.com/OC74t.png
What is happening is that the return on line 54 executes before all elements of postIDs is looped through because of which, an empty array is returned back to the component.
Let me know if further details are required. Please help me out. Thanks in advance!
Try to change your loop to a for...of:
for (const postID of currentUserData.uploads) {
const postReference = doc(db, `posts/${postID}`)
const snapshot = await getDoc(postReference)
const postData = snapshot.data()
postData.time = postData.time.toJSON()
uploadsArray.push(postData)
}
return { props: { uploadsArray }}
What about try to use Promise.all?
var promises = [];
promises.push();
// Wait for all promises to resolve
Promise.all(promises).then(function(res) {
// Do something...
});

How to use Promise.all with multiple Firestore queries

I know there are similar questions to this on stack overflow but thus far none have been able to help me get my code working.
I have a function that takes an id, and makes a call to firebase firestore to get all the documents in a "feedItems" collection. Each document contains two fields, a timestamp and a post ID. The function returns an array with each post object. This part of the code (getFeedItems below) works as expected.
The problem occurs in the next step. Once I have the array of post ID's, I then loop over the array and make a firestore query for each one, to get the actual post information. I know these queries are asynchronous, so I use Promise.all to wait for each promise to resolve before using the final array of post information.
However, I continue to receive "undefined" as a result of these looped queries. Why?
const useUpdateFeed = (uid) => {
const [feed, setFeed] = useState([]);
useEffect(() => {
// getFeedItems returns an array of postIDs, and works as expected
async function getFeedItems(uid) {
const docRef = firestore
.collection("feeds")
.doc(uid)
.collection("feedItems");
const doc = await docRef.get();
const feedItems = [];
doc.forEach((item) => {
feedItems.push({
...item.data(),
id: item.id,
});
});
return feedItems;
}
// getPosts is meant to take the array of post IDs, and return an array of the post objects
async function getPosts(items) {
console.log(items)
const promises = [];
items.forEach((item) => {
const promise = firestore.collection("posts").doc(item.id).get();
promises.push(promise);
});
const posts = [];
await Promise.all(promises).then((results) => {
results.forEach((result) => {
const post = result.data();
console.log(post); // this continues to log as "undefined". Why?
posts.push(post);
});
});
return posts;
}
(async () => {
if (uid) {
const feedItems = await getFeedItems(uid);
const posts = await getPosts(feedItems);
setFeed(posts);
}
})();
}, []);
return feed; // The final result is an array with a single "undefined" element
};
There are few things I have already verified on my own:
My firestore queries work as expected when done one at a time (so there are not any bugs with the query structures themselves).
This is a custom hook for React. I don't think my use of useState/useEffect is having any issue here, and I have tested the implementation of this hook with mock data.
EDIT: A console.log() of items was requested and has been added to the code snippet. I can confirm that the firestore documents that I am trying to access do exist, and have been successfully retrieved when called in individual queries (not in a loop).
Also, for simplicity the collection on Firestore currently only includes one post (with an ID of "ANkRFz2L7WQzA3ehcpDz", which can be seen in the console log output below.
EDIT TWO: To make the output clearer I have pasted it as an image below.
Turns out, this was human error. Looking at the console log output I realised there is a space in front of the document ID. Removing that on the backend made my code work.

Best way to return full object made from data from different APIs

Im working on an app that mainly is a large form that contains several dropdowns. These dropdowns should
populate with some data from the DB. The app has a server with Express that it works as a proxy: I call it from the front end
and then that server calls some external API's, format the info and then send them back to the front.
Im thinking on having on the Backend a route like "/dropdown" call that route from the front end. And once I get the data (I would like to receive it like this)
data: {
dataForDropdown1:[data],
dataForDropdown2:[data],
dataForDropdown3:[data],
dataForDropdown4:[data],
...etc
}
store it on Redux and call them with a selector and populate all the dropdowns required.
The problem is on the server. I need to get that info from different APIs so in the route in Express I was thinking on use something like
Promise.all([promisefetchUrl1],[promisefetchUrl2],[promisefetchUrl3],...etc)
but I don't know how to format like the object above, because as I understand Promise.all doesn't have an order it just returns the info with the first promise resolved, then the second, etc so it would be hard to know
which info is which.
I was thinking on using async await but its way too dirty, like this:
const info1 = await fetch(url1)
const info2 = await fetch(url2)
const info3 = await fetch(url3)
const info4 = await fetch(url4)
etc
then return it like this
const data = {
dataForDropdown1:info1.data,
dataForDropdown2:info2.data,
dataForDropdown3:info3.data,
dataForDropdown4:info4.data
...etc
}
any advices?
Promise.all doesn't have an order it just returns the info with the first promise resolved, then the second, etc so it would be hard to know which info is which.
It does have an order - the first element in the resolve array will correspond to the first Promise in the array passed to Promise.all, etc, regardless of the order in which the promises resolve.
Use:
const results = await Promise.all([
getData(promisefetchUrl1),
getData(promisefetchUrl2),
getData(promisefetchUrl3),
getData(promisefetchUrl4), // this could be made less repetitive
]);
const data = {
dataForDropdown1: results[0],
dataForDropdown2: results[1],
dataForDropdown3: results[2],
dataForDropdown4: results[3],
};
where getData takes the URL and returns a Promise that resolves to the data corresponding to the URL.

Zomato-API behaving weirdly different api calls

const zomato = require("zomato-api");
const client = zomato({
userKey: "my-user-key",
});
// fetching one data and chaining another fetch
client.getGeocode({lat: lat-value, lon: lon-value}).then(result => {
console.log(result);
// now using the data fetched we get the restaurant details
return client.getRestaurant({res_id: result.popularity.nearby_res[0]})
}).then(res_data => {
console.log(res_data);
});
So, the idea was to extract the nearby_res array from the geocode API's result and then use one of the elements (each element is an id) as the parameter for the next API call.
client.getRestaurant({res_id: result.popularity.nearby_res[0]})
Now, this should originally return all the details about the restaurant with the id specified.
When invoked independently with an id, the getRestaurant() function returns the result in the expected format. But when it is chained like this, the result is basically the same as the result of the first API call ( geocode API).
Am I doing anything wrong here? or is the Zomato API reluctant to do this kind of chaining.
Please help.

fetching multiple urls from an api

Basically I am working with a star wars API called swapi (i haven't worked with APIs before) and I am fetching the data with a simple async-await function.
My goal is to get all the movies that API holds (a total of 6 of them) I am using a template tag in HTML and I'm cloning it in javascript and then displaying all 6 movies.
So to clarify, I am getting an array of 6 objects that I'm displaying the title of each movie in HTML without a problem since the title is in a string format, but every object has also a key (characters) that has a value of an array and inside that array is a big list of characters that play in the movie but they are in a URL format (http://swapi.dev/api/people/1/) except the last number in the URL changes for each of them.
Is there a smart way to fetch and display all the character names for each movie they have played in? because all the ways I'm trying aren't working. The ideal solution would be to display all the characters that have played in each movie and having the possibility to click on them and seeing a few details that they hold.
so this is my guess (I have no time to test this second, but will shortly and get this answer working don't pass.)
async function getSWdata(){
await fetch('starwars api')
.then(res=>res.json())
.then(data=>data.people.map(async (x)=>await fetch(x).then(res=>res.json())));
}
the things I'm unsure about are the exact syntax of async => functions, or any complications of async functions nested inside an async function...
but this might get you on the right track regardless.
EDIT:::
this below is working mostly for me (I am iffy sure on promises => there are improvements to be made)
async function getSWdata(){
return await fetch('https://swapi.dev/api/films')
.then(res=>res.json())
.then(data=>
{
const r = data.results.map((results)=>
{
const toons = results.characters.map(async (toon)=>await fetch(toon).then(res=>res.json()))
results.characters = toons;
return results;
})
data.results = r;
return data;
});
}
const SWData = getSWdata();
console.log(SWData);

Categories

Resources