Pokemon API, Promises javascript get data inside of array json - javascript

I have been working to make a small app to get the images and info from the pokemon api at http://pokeapi.co/ , I am following course using promises however I can get a group (example: water type) which give me 78 objects , each one with a resource_uri which is the data which give me the information of each pokemon.
Until now I have make this and I can get all the objects, however, now how can I make in order to get for each object push in the console.log (or later use them) all the 78pokemons with the data of each.
My code until now is this>
var $ = window.jQuery
var base = 'http://pokeapi.co/api/v1/egg/'
Promise.resolve($.get(base + '2'))
.then((results) =>
.then((results) => {
var pokechara = results.pokemon
var basechara = 'http://pokeapi.co'
var promises = []
for (let chara of pokechara){
var pokech = pokechara[i]
'${something}'
var pokechurl = basechara + pokechara[0].resource_uri
promises.push(Promise.resolve($.get(pokechurl)))
}
debugger
return Promise.all(promises)
})
.then((poke) => {
console.log(poke)
})
.catch((err) => {
debugger
})
I really wanted to make something with the api of yugioh.wikia but I dont see how I can get work because the problem with the Cros-server or header. To see a preview of what I am doing you can see at http://www.kengreg.com/yugiohapp/
Thanks in advance

Actually, in the code used in your reply to Alex, the string variables you use to call the api are the only thing wrong, the 'http://' part at the start is needed. Apart from that, your code works fine.
var $ = window.jQuery;
var base = 'http://pokeapi.co/api/v1/egg/';
Promise.resolve($.get(base + '2'))
.then((results) => {
var pokechara = results.pokemon;
var basechara = 'http://pokeapi.co/';
var promises = [];
for (var i in pokechara){
var pokech = pokechara[i];
var pokechurl = basechara + pokechara[0].resource_uri;
promises.push(Promise.resolve($.get(pokechurl)));
}
debugger
return Promise.all(promises);
})
.then((poke) => {
debugger;
console.log(poke);
})
.catch((err) => { debugger })
I left the debugger so you can checkout the results of the promises. The poke variable at the end should have the objects array you wanted.

Related

Push inside forEach with query not working properly

I'm working with mongodb stitch/realm and I'm trying to modify objects inside an array with a foreach and also pushing ids into a new array.
For each object that i'm modifying, I'm also doing a query first, after the document is found I start modifying the object and then pushing the id into another array so I can use both arrays later.
The code is something like this:
exports = function(orgLoc_id, data){
var HttpStatus = require('http-status-codes');
// Access DB
const db_name = context.values.get("database").name;
const db = context.services.get("mongodb-atlas").db(db_name);
const orgLocPickupPointCollection = db.collection("organizations.pickup_points");
const orgLocStreamsCollection = db.collection("organizations.streams");
const streamsCollection = db.collection("streams");
let stream_ids = [];
data.forEach(function(stream) {
return streamsCollection.findOne({_id: stream.stream_id}, {type: 1, sizes: 1}).then(res => { //if I comment this query it will push without any problem
if(res) {
let newId = new BSON.ObjectId();
stream._id = newId;
stream.location_id = orgLoc_id;
stream.stream_type = res.type;
stream.unit_price = res.sizes[0].unit_price_dropoff;
stream._created = new Date();
stream._modified = new Date();
stream._active = true;
stream_ids.push(newId);
}
})
})
console.log('stream ids: ' + stream_ids);
//TODO
};
But when I try to log 'stream_ids' it's empty and nothing is shown. Properties stream_type and unit_price are not assigned.
I've tried promises but I haven't had success
It's an asynchronous issue. You're populating the value of the array inside a callback. But because of the nature of the event loop, it's impossible that any of the callbacks will have been called by the time the console.log is executed.
You mentioned a solution involving promises, and that's probably the right tack. For example something like the following:
exports = function(orgLoc_id, data) {
// ...
let stream_ids = [];
const promises = data.map(function(stream) {
return streamsCollection.findOne({ _id: stream.stream_id }, { type: 1, sizes: 1 })
.then(res => { //if I comment this query it will push without any problem
if (res) {
let newId = new BSON.ObjectId();
// ...
stream_ids.push(newId);
}
})
})
Promise.all(promises).then(function() {
console.log('stream ids: ' + stream_ids);
//TODO
// any code that needs access to stream_ids should be in here...
});
};
Note the change of forEach to map...that way you're getting an array of all the Promises (I'm assuming your findOne is returning a promise because of the .then).
Then you use a Promise.all to wait for all the promises to resolve, and then you should have your array.
Side note: A more elegant solution would involve returning newId inside your .then. In that case Promise.all will actually resolve with an array of the results of all the promises, which would be the values of newId.

asynchronous loop for in Javascript

I'm trying to iterate and print out in order an array in Javascript that contains the title of 2 events that I obtained from doing web scraping to a website but it prints out in disorder. I know Javascript is asynchronous but I'm new in this world of asynchronism. How can I implement the loop for to print the array in order and give customized info?
agent.add('...') is like console.log('...'). I'm doing a chatbot with DialogFlow and NodeJs 8 but that's not important at this moment. I used console.log() in the return just for debug.
I tried the next:
async function printEvent(event){
agent.add(event)
}
async function runLoop(eventsTitles){
for (let i = 0; i<eventsTitles.length; i++){
aux = await printEvent(eventsTitles[i])
}
}
But i got this error error Unexpected await inside a loop no-await-in-loop
async function showEvents(agent) {
const cheerio = require('cheerio');
const rp = require('request-promise');
const options = {
uri: 'https://www.utb.edu.co/eventos',
transform: function (body) {
return cheerio.load(body);
}
}
return rp(options)
.then($ => {
//** HERE START THE PROBLEM**
var eventsTitles = [] // array of event's titles
agent.add(`This mont we have these events available: \n`)
$('.product-title').each(function (i, elem) {
var event = $(this).text()
eventsTitles.push(event)
})
agent.add(`${eventsTitles}`) // The array prints out in order but if i iterate it, it prints out in disorder.
// *** IMPLEMENT LOOP FOR ***
agent.add(`To obtain more info click on this link https://www.utb.edu.co/eventos`)
return console.log(`Show available events`);
}).catch(err => {
agent.add(`${err}`)
return console.log(err)
})
}
I would like to always print out Event's title #1 and after Event's title #2. Something like this:
events titles.forEach((index,event) => {
agent.add(`${index}. ${event}`) // remember this is like console.log(`${index}. ${event}`)
})
Thanks for any help and explanation!
There no async case here but if you still face difficultly than use this loop
for (let index = 0; index < eventsTitles.length; index++) {
const element = eventsTitles[index];
agent.add(${index}. ${element})
}

Fetching data in the loop

So I'm trying to connect to external server called Pexels to get some photos. I'm doing that from node.js but it is just a javascript issue. Pexels unfortunately lets user to download object with only 40 pictures per page.
https://api.pexels.com/v1/curated?per_page=40&page=1 // 40 is maximum
But actually I need more then that. I'd like to get 160 results, ie. to combine all first four pages. In order to do that I tried looping the request:
let pexelsData = [];
for(let i = 1; i < 5; i++) {
const randomPage = getRandomFromRange(1, 100); //pages should be randomized
const moreData = await axios.get(`https://api.pexels.com/v1/curated?per_page=40&page=${randomPage}`,
createHeaders('bearer ', keys.pexelsKey));
pexelsData = [ ...moreData.data.photos, ...pexelsData ];
}
Now I can use pexelsData but it work very unstable, sometimes it is able to get all combined data, sometimes it crashes. Is there a correct and stable way of looping requests?
You work with 3rd party API, which has rate limits. So you should add rate limits to your code. The simplest solution for you is using p-limit or similar approach form promise-fun
It will looks like that:
const pLimit = require('p-limit');
const limit = pLimit(1);
const input = [
limit(() => fetchSomething('foo')),
limit(() => fetchSomething('bar')),
limit(() => doSomething())
];
(async () => {
// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);
})();
you can break it into functions like..
let images=[];
const getResponse = async i=> {
if(i<5)
return await axios.get(`https://api.pexels.com/v1/curated?per_page=40&page=${i}`)
}
const getImage = (i)=>{
if(i<5){
try {
const request = getResponse(i);
images = [...images,...request];
// here you will get all the images in an array
console.log(images)
getImage(++i)
} catch (error) {
console.log("catch error",error)
// getImage(i)
}
}
}
getImage(0); //call initail

Vue.js combine data from RESP API

I need combine multple API calls on a final object, this because API have limits to be consumed, any have an idea how is possible combine multiple calls in same final object, next is an example of my code, I need all data in this.lista but is not working:
created(){
this.$http.get('/api/transactions?senderId=8642612272713533685S&limit=1&offset=000')
.then( function(res){
console.log(res.body.count);
let limit = Math.ceil(res.body.count/1000);
console.log(limit);
let m = {};
let off = 0;
for (var i = 0; i <= limit; i++) {
this.$http.get('/api/transactions?senderId=8642612272713533685S&limit=1000', {params:{offset: off}})
.then( function(data){
this.lista = { ...this.lista, ...data.body.transactions }
} )
off = off + 1000;
}
}
);
}
any help will be appreciated
Using Promise.all is most likely what you are looking for. I will write just enough code for you to understand where to go.
// Populate your array array with URLs you want to get
let urls = ["url1", "url2", "...and so on"];
// Make into web request promises
let httpReqPromises = urls.map( url => this.$http.get(url) )
// Wait for all of them to resolve
Promise.all(httpReqPromises).then(allResponses => {
// Put them all together
this.lista = allResponses.reduce((a, b) => ({...a, ...b}, {})
})
The only work I leave up to you is how you populate the url variable.

React Axios API call with array loop giving wrong order?

I was learning react and doing some axios api call with an array. I did a code on gathering data through coinmarketcap api to learn.
So, my intention was to get the prices from the api with a hardcoded array of cryptocurrency ids and push them into an array of prices. But I ran into a problem with the prices array, as the prices were all jumbled up. I was supposed to get an array in this order
[bitcoinprice, ethereumprice, stellarprice, rippleprice]
but when I ran it in the browser, the prices came randomly and not in this order, sometimes I got my order, sometimes it didn't. I used a button which onClick called the getPrice method. Does anyone know what went wrong with my code? Thanks!
constructor(){
super();
this.state = {
cryptos:["bitcoin","ethereum","stellar","ripple"],
prices:[]
};
this.getPrice = this.getPrice.bind(this);
}
getPrice(){
const cryptos = this.state.cryptos;
console.log(cryptos);
for (var i = 0; i < cryptos.length; i++){
const cryptoUrl = 'https://api.coinmarketcap.com/v1/ticker/' + cryptos[i];
axios.get(cryptoUrl)
.then((response) => {
const data = response.data[0];
console.log(data.price_usd);
this.state.prices.push(data.price_usd);
console.log(this.state.prices);
})
.catch((error) => {
console.log(error);
});
}
}
If you want to receive the data in the order of the asynchronous calls you make, you can use Promise.all, that waits until all the promises of an array get executed and are resolved, returning the values in the order they were executed.
const cryptos = ['bitcoin', 'ethereum', 'stellar', 'ripple'];
const arr = [];
for (var i = 0; i < cryptos.length; i++){
const cryptoUrl = 'https://api.coinmarketcap.com/v1/ticker/' + cryptos[i];
arr.push(axios.get(cryptoUrl));
}
Promise.all(arr).then((response) =>
response.map(res => console.log(res.data[0].name, res.data[0].price_usd))
).catch((err) => console.log(err));
You could use a closure in the for loop to capture the value of i and use it as the index once the data is returned rather than using push:
getPrice(){
const cryptos = this.state.cryptos;
console.log(cryptos);
for (var i = 0; i < cryptos.length; i++) {
const cryptoUrl = 'https://api.coinmarketcap.com/v1/ticker/' + cryptos[i];
(function (x) {
axios.get(cryptoUrl)
.then((response) => {
const data = response.data[0];
console.log(data.price_usd);
var newPrices = this.state.prices;
newPrices[x] = data.price_usd;
this.setState({prices: newPrices});
console.log(this.state.prices);
})
.catch((error) => {
console.log(error);
});
})(i);
}
}

Categories