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.
Related
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
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.
Basically, I need to fetch and use promises in order to do this exercise. However, I cannot get the results I want. The goal is to fetch data from the iTunes API and encode the response as JSON, passing it into my helper function.
//What I've tried
const URL_TEMPLATE = "https://itunes.apple.com/search?entity=song&limit=25&term={searchTerm}";
function fetchTrackList(param) {
let url = URL_TEMPLATE.replace('{searchTerm}', param);
let promise = fetch(url);
promise.then(function(res) {
return res.json();
})
.then(function(res) {
renderSearchResults(res);
});
}
//My render methods
function renderTrack(track) {
let newDiv = $('<img>');
newDiv.attr({src: track.artworkUrl100, alt: track.trackName, title: track.trackName});
$('#records').append(newDiv);
}
function renderSearchResults(obj) {
$('#records').empty();
obj.results.forEach(result => {
renderTrack(result);
})
}
//Now it's the time to practice using `fetch()`! First, modify the `index.html`
//file to load the polyfills for _BOTH_ the fetch() function and Promises, so
//that your example will work on Internet Explorer.
//Use version 2.0.4 of the `fetch` polyfill.
//Define a function `fetchTrackList()` that takes in a "search term" string as a
//parameter and uses the `fetch()` function to downloads a list of tracks from
//the iTunes Search API. You can use the below `URL_TEMPLATE` string for the URL,
//replacing `"{searchTerm}"` with the passed in search term (no {})
//Send the AJAX request, _then_ encode the response as JSON once it is received,
//and _then_ should call you `renderSearchResults() function and pass it the
//encoded data.
//
//IMPORTANT: Your `fetchTrackList()` method must also _return_ the Promise
//returned by the end of the `.then()` chain! This is so the method itself will
//be asynchronous, and can be further chained and utilized (e.g., by the tester).
//
//You can test this function by calling the method and passing it the name of
//your favorite band (you CANNOT test it with the search button yet!)
const URL_TEMPLATE = "https://itunes.apple.com/search?entity=song&limit=25&term={searchTerm}";
I expect tracks to actually render, however; nothing renders. I can only assume I've done something wrong, but do not know where to go about it.
I'm trying to query an API to get some data then I want to upsert all of it into my table.
But for some reason I'm not having any luck.
What's the best way to go about this?
I don't think my method of doing a query in a loop is best.
var coin = new Parse.Object.extend("Coins");
axios.get('https://api.coinmarketcap.com/v1/ticker/')
.then(response => {
let data = response.data;
// Put into database
data.map(entry => {
let q = new Parse.Query(Model.Coins.className());
q.equalTo('symbol', entry.symbol);
q.first()
.then(record => {
record.set('symbol', entry.symbol);
record.set('price_usd', entry.price_usd);
return record.save(null, {useMasterKey: true});
});
});
res.success(response);
});
you should avoid fetching and updating objects in a loop. In order to make it better you need to use 2 things:
In your query, instead of using equalTo and first you need to use containedIn for query all the records in one call. Then you need to iterate on the query results, for each record in the loop you need to do the following:
record.set('symbol', entry.symbol);
record.set('price_usd', entry.price_usd);
Finally you need to use saveAll to save all the objects in one call (please notice that saveAll is static function of Parse.Object and you should pass an array into it. Please review the docs before doing it)
Check your data. You may find you have unexpectedly updated records.
Assuming that's the entire body of a cloud function, your function initiates an asynchronous server call, then immediately tells the requestor that the operation was successful, but response isn't populated yet so you pass back undefined. However, parse-server will still run that asynchronous code.
The solution is to put the res.success call inside another .then chain, so the function won't return a response until after the server call + save finishes.
You're also going to get an uncaught error if the symbol doesn't exist on your table, though. You don't check to make sure the query returned a response to the first() call.
I'm having an issue with successive API calls (using JQuery's AJAX) to two different APIs in order to build objects with certain attributes. Here's the summary of my app and what I'm trying to do:
The user enters in the name of an actor or director, and the app is meant to return a total of five movies, each of which has certain attributes like title, overview, year, budget, revenue, and a link to a YouTube preview. I'm using The Movie Database API, plus the YouTube API for the YouTube link.
Here's the order of how things currently to work, with all of this happening in the action creator of the Redux app:
Actor name gets sent to the TMDB API -- returns ActorID number
ActorID number gets sent to the TMDB API -- returns 20 movies with: title, overview, year, poster link, and MovieID number
For EACH movie in that list, the MovieID number gets sent to the API -- returns more attributes: budget, revenue, and IMDB-ID (to use in a link later)
Also for EACH movie in step 2, the title gets sent to the YouTube API -- returns a link to the preview.
Once all of this information is assembled for each movie, I want to return the first five movies and dispatch them as the action payload to the Redux store.
I'm using some promises, and I've tried everything I could think of in terms of rearranging the flow of functions, but I can't get all the information I need with one click of the submit button. The funny thing is, it works with TWO clicks of the submit button, I think because by then all the async AJAX calls are finally done. But after the first click, I have an empty array where the movie objects should be.
Here's some code that should summarize what things look like:
var personId
var movies = []
function actorByRating(UserInput) {
Step 1: get actor ID number:
function searchActors() {
return $.ajax({
method: "GET",
url: `https://api.themoviedb.org/3/search/person?query=${UserInput}&api_key=<key>`
}).done(function(response){
personId = response.results[0].id
})
}
Step 2: Use Actor ID to get list of movies, start assigning them attributes:
function getMovies() {
$.ajax({
method: "GET",
url: `https://api.themoviedb.org/3/discover/movie?with_cast=${personId}&vote_count.gte=20&sort_by=vote_average.asc&budget.desc&api_key=<key>&include_image_language=en`
}).done(function(response) {
response.results.forEach((m) => {
var movie = {}
movie.title = m.title
movie.year = m.release_date.split("-")[0]
movie.movieId = m.id
movie.overview = m.overview
movie.poster = "http://image.tmdb.org/t/p/w500" + m.poster_path
getMovieInfo(movie) //step 3
getYouTube(movie) //step 4
saveMovie(movie)
})
})
}
function saveMovie(movie){
movies.push(movie)
}
Step 3 function, takes in a movie object as an argument:
function getMovieInfo(m){
return $.ajax({
method: "GET",
url: `https://api.themoviedb.org/3/movie/${m.movieId}?&api_key=<key>&append_to_results=imdb_id`
}).done(function(response) {
m.revenue = response.revenue
m.budget = response.budget
m.imdbId = response.imdb_id
})
}
Step 4 function, to get Youtube link. Also takes a movie object:
function getYouTube(movie){
$.ajax({
method: "GET",
url: `https://www.googleapis.com/youtube/v3/search?part=snippet&q=${movie.title.split(" ").join("+")}+trailer&key=<key>`
}).done(function(yt){
movie.youtubeLink = `http://www.youtube.com/embed/${yt.items[0].id.videoId}`
})
}
After this, the filtering functions work fine, when they have an array of movies to work with. The problem is, I think, all these successive API calls keep firing before the previous ones are done, and the latter ones need info from the earlier ones to search with. Thus, when I click submit the first time, the final movies array is empty, so the dispatched payload is an empty array. THEN the movie objects get filled in, so when you click submit again, the movies are already there to work with, and the rest of the app works fine.
I've tried everything I can think of to slow the process down, chain promises together (which doesn't work because Step 2 has to run for several movies, i.e. the return values of each function keep changing, so I can't ".then" them), reorganizing the information that comes in...but I can't get it to give me movie objects with all the attributes I need by the time the filtering functions actually run to create the proper payload.
Any help or suggestions would be greatly appreciated!
(Note: the "key" stuff above is just placeholder text)
UPDATE:
I changed the code to basically the following:
searchActors()
.then(function(response){
const actorId = response.data.results[0].id
return actorId
})
.then((personID) => {
return getMoviesFromPersonID(personID)
})
.then(function(response) {
const movieList = []
response.data.results.forEach((m) => {
var movie = {}
movie.title = m.title
movie.year = m.release_date.split("-")[0]
movie.movieId = m.id
movie.overview = m.overview
movie.poster = "http://image.tmdb.org/t/p/w500" + m.poster_path
movieList.push(movie)
// saveMovie(movie)
})
return Promise.all(movieList)
})
.then((movieList) => {
const deepMovieList = []
movieList.forEach((movie) => {
getMovieInfo(movie)
.then(function(response) {
movie.revenue = response.data.revenue
movie.budget = response.data.budget
movie.imdbId = response.data.imdb_id
deepMovieList.push(movie)
})
})
return Promise.all(deepMovieList)
})
.then((deepMovieList) => {
const finalMovies = []
deepMovieList.forEach((movie) => {
finalMovies.push(getYouTube(movie))
})
return Promise.all(finalMovies)
})
Everything works fine right up until the first mention of "deepMovieList". I can't seem to figure out how to have that particular step to work properly, as it essentially involves making 20 API calls with each movie in the movieList. I can't figure out how to 1) get the info back from the API, 2) assign the attributes to the movie object that is passed in to getMovieInfo, and then 3) push that movie object (with the new attributes) to an array that I can use Promise.all on, all without interrupting the promise chain.
Either it moves on to the next "then" function too early (while deepMovieList is still an empty array), or, with other random stuff I've tried, the array ends up being undefined.
How can I have the next "then" function wait until 20 API calls have been made and each movie object has its updated attributes? This will also run into the same problem in the next step, for the YouTube link.
Thanks!
TL;DR: use fetch and promises instead of jQuery, group promises using Promise.all.
The Longer Version
Ok, I'm not going to repeat all your code here. I'm going to abbreviate some stuff to keep it simple.
Basically, you have a bunch of tasks to perform. I'm going to pretend each of them is a function that returns a promise which is resolved with the data you want.
searchActor() - returns a promise resolved with some ID number
getMoviesFromActorID(actorId) - returns a promise that resolves with an array of movie IDs
getMovie(movieId) - returns a promise that resolves with the details for the given movie ID
getYoutube(movie) - returns a promise that resolves with the Youtube embed code.
Given this basic setup (and I admit I'm leaving out a lot of stuff), the code looks like this:
// search for an actor
searchActor('Brad Pitt')
// then get the movie IDs for that actor
.then((actorId) => getMoviesFromActorID(actorId))
// then iterate over the list of movie IDs & build an array of
// promises. Use Promise.all to create a new Promise which is
// resolved when all are resolved
.then((movieIdList) => {
const promiseList = [];
movieIdList.forEach((id) => promiseList.push(getMovie(id)));
return Promise.all(promiseList);
})
// then get Youtube links for each of the movies
.then((movieDetailsList) => {
const youtubeList = [];
movieDetailsList.forEach((movie) => youtubeList.push(getYoutube(movie)));
return Promise.all(youtubeList);
})
// then do something with all the information you've collected
.then((finalResults) => {
// do something interesting...
});
The key to this is Promise.all (documentation here), which will take an array of Promises (or any other iterable object containing promises) and create a new Promise which will resolve when all of the original promises have resolved. By using Promise.all, you can create a step in your promise chain which can include a variable number of parallel actions which must complete before the next step.
You could do something like this will jQuery and callbacks, but it would be pretty darn ugly. One of the great benefits of promises is the ability to lay out a series of steps like above.