How to access date in next .then() - fetch api - javascript

I wonder if there is a way to access data from then on the next one? Code looks like this:
fetch(`http://localhost:3003/users/${userObject.id}`)
.then(res => res.json())
.then(user => {
...
})
.then(???)
and in second then I have all the needed info about the user. When I put everything in second then it works, but code is very messy and repetitive and I would like to put some things into function. Unfortunately, in that case, I don't have access to some data...
Any ideas? Thanks!

You can pass an argument to the next promise by returning it from the previous one.
fetch(`http://localhost:3003/users/${userObject.id}`)
.then(res => res.json())
.then(user => {
return user.id;
})
.then(userId => {
console.log('user id is:', userId);
});
Also, you can accomplish same result by using async programming like bellow:
async function fetchSomeData() {
var res = await fetch(`http://localhost:3003/users/${userObject.id}`);
var user = await res.json();
return user;
}
fetchSomeData().then(user => {
console.log('user id is:', user.id)
});

but code is very messy and repetitive and I would like to put some
things into function
Just use async/await syntax, it's much more understandable.
(async() => {
const request = await fetch(`http://localhost:3003/users/${userObject.id}`);
const result = await request.json();
// proceed to do whatever you want with the object....
})();
This is a self-executing function, but you can also declare this in the following way:
const myFunc = async() => {
const request = await fetch(`http://localhost:3003/users/${userObject.id}`);
const result = await request.json();
// your logic here or you can return the result object instead;
};
or even without arrow functions:
const myFunc = async function() {
const request = await fetch(`http://localhost:3003/users/${userObject.id}`);
const result = await request.json();
console.log(result.id);
};

Related

Store fetch data in variable to access it later

I'm facing a probably super easy to solve problem regarding fetching.
I'd like to fetch some json datas and store it in a variable to access it later.
The problem is that I always ends up getting undefined in my variable. What's the way to do to deal with that kind of data storing ?
Here's my code.
const fetchCities = () => {
fetch('cities.json')
.then(response => response.json())
.then(data => {
return data;
});
}
let cities = fetchCities();
console.log(cities)
Already looked up for answers but couldn't find a way to do. Thanks !
You could do this very simply with async/await like this:
const fetchCities = async () => {
let cities = await fetch('cities.json');
return cities.json();
};
let cities = await fetchCities();
console.log(cities);
Sending a fetch request takes time, so the console.log works before the data arrives.
The best way to deal with fetch is using async functions and await like so:
const fetchCities = ()=>{
return fetch('cities.json');
}
async function main(){
try {
const res = await fetchCities();
const data = await res.json();
// handle the data here, this will work only after the data arrival
console.log(data);
} catch (err) {
console.log(err);
}
}
main();
Note: await can only be used in async functions, that's the main purpose of the main function.
Or if you want to use .then:
const fetchCities = ()=>{
return fetch('cities.json');
}
function main(){
fetchCities()
.then(res => res.json())
.then(data => {
// handle the data here, all you code should be here
})
.catch (err => console.log(err));
}
main();

How can I retrieve and loop through data retrieved from a fetch request?

I am using an open-source api to retrieve breweries when people search by city name. I can console. log the promise returned but when I try to loop and console.log the data it tells me undefined.
const searchBtn = document.getElementById('beer-search-button');
const getBeerData = (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${cityName}`;
encodeURI(beerApi);
fetch(beerApi)
.then(res => {
if(res.ok) {
console.log(res.json());
for(let b in res) {
console.log(b.name);
}
} else {
console.log('Error!');
}
});
}
searchBtn.addEventListener('click', function(e) {
e.preventDefault;
let searchQuery = document.getElementById('city-input').value;
getBeerData(searchQuery);
});
You need to loop over the result of res.json(). You do this with another .then().
And calling encodeURI() without using the result has no effect. You should be calling encodeURIComponent() on the city name, and using that in the URI.
const getBeerData = (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${encodeURIComponent(cityName)}`;
fetch(beerApi)
.then(res => {
if (res.ok) {
return res.json()
} else {
throw "Error";
}
}).then(res => res.forEach(b => console.log(b.name)));
}
You've logged the promise but you haven't parsed that JSON. You can't loop over an array if it doesn't exist. And, because it's an array you should be using a for/of loop for (const b of data)....
Here's a shortened version.
// Get the data
fetch(beerApi)
// Parse the data
.then(res => res.json())
// Loop over the data
.then(data => {
for (const b of data) {
console.log(b.name);
}
});
});
res.json() also returns a Promise which you need to await either using then() or using await which is certainly my preferred option.
Please note that there is no need to URL encode the whole string as the API's URL is already encoded correctly, so you just need to URI encode the city name. Another thing you should probably do, is wait for the DOM to be loaded using DOMContentLoaded event before assigning event listeners as otherwise problems could occur because the DOM element might not yet be present.
const getBeerData = async (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${encodeURIComponent(cityName)}`;
const res = await fetch(beerApi);
if (res.ok) {
const breweries = await res.json();
breweries.forEach(brewery => console.log(brewery));
} else {
console.log("Error!");
}
};
window.addEventListener("DOMContentLoaded", event => {
const searchBtn = document.getElementById("beer-search-button");
searchBtn.addEventListener("click", async function (e) {
e.preventDefault;
let searchQuery = document.getElementById("city-input").value;
await getBeerData(searchQuery);
});
})
<input type="text" id="city-input" name="city-input">
<button id="beer-search-button">Search for breweries!</button>

Axios console.log data but return Promise <pending>

I've trying to retrieve the data, but I can't return it, can only see it in the console,
it's a simple axios get function but for some reason, I keep getting Promise even after using async/await.
my goal is to save the data to the memory.
any help would really be appreciated
let fetchTodo = async () => {
await axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(res.data))
.then(res => { return res })
.catch(err => console.log(err))
};
console.log("TEST: ", fetchTodo())
console
Asycn function always returns a promise, to get data from the fetchTodo function you need to create another async function which will await the result returned by fetchTodo(). if you are using react, you can use states and update the state while you are inside the .then chain of the fetchTodo function.
Asycn function always returns a promise. For getting or saving data you need to get it from .then() function. Here you can check the example. Hope so it will help you.
let fetchTodo = async () => {
await axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(res.data))
.then(res => {
// here you can performance your task, save data, send
// response or anything else
return res
})
.catch(err => console.log(err))
};
fetchTodo()
The async/await syntax means a function will return a Promise.
If you want to return the value, you could do something like this:
let fetchTodo = async () => {
try {
const res = await axios.get("https://jsonplaceholder.typicode.com/todos/1");
return res;
} catch (error) {
console.log(error);
}
};
// For the folowing code to work, it must be placed inside a async function as well
const res = await fetchTodo();
console.log(`Test: ${res.data}`);
// If it's a Top level call, use the folowing code
const res = fetchTodo().then( res => {
const data = res.data;
// The rest of your code goes here.
// ...
// ...
// ...
}).catch( error => {
console.log(error);
});
Some more information about it on: How can I use async/await at the top level?

How to await on a promise that is returned in an array without destructuring first?

If I have something like,
const apiCall = async (url) => {
try {
const { data } = await axios.get(url);
return [url, data];
} catch ({ response: { data } }) {
console.log('Error', data);
}
}
Say I want to call and access the data from the promise. I'd have to do something like,
const [, call] = await validate('/api/root');
const data = await call;
Is there a way to do this in a one liner, without having to access the call, something like,
await (await validate('/api/root'))?
This is an equivalent one-liner:
const data = await (await validate('/api/root'))[1]
You can put an awaited function inside an argument. So something like
const result = await apiCall(
await validate(),
url
)
Then you could handle the validation inside apiCall.
Or you could just add the validate function as a callback inside apiCall if it's dependent on the result of apiCall.

Webscraper function returns undefined

Im making a webscraping function to make a json with the data, the webscraper part works, wierd thing is that the function returns undefined
getproduct.js
module.exports.getproduct = url => {
fetch(url)
.then(response => response.text())
.then(body => {
let product;
const $ = cheerio.load(body);
product = {
productName: $(".product-name").text()
};
console.log(product);
return product;
});
};
index.js
const {getproduct} = require('./webScraper/getproduct');
console.log(getproduct('https://www.americanas.com.br/produto/134118928'));
the console.log(product); works fine, but the console.log on the index.js prints nothing. What im missing?
Every return statement in javascript only belongs to it's closest surrounding function. You have one return statement in your code, and it belongs to a different function than you might expect:
.then(body => {
...
return product;
})
So the return statement will only return a value to that function.
You main function, getproducts, actually has no return statements in it, thus it does return undefined. Adding a return in front of your fetch solves that, but we are not yet done:
return fetch(url)
Because fetch and the .then-s that follow will not just return the value. The return a Promise. Promises are hard concepts, and something I will not be able to explain here, so I would suggest reading more about that if you are not sure about them yet :)
The main take-away is to get the value out of the promise, you have to use .then or await, more on await later, lets stay with .then first:
getproduct('https://www.americanas.com.br/produto/134118928')
.then(product => {
console.log('product:', product);
});
Now, people realized that writing all your code that does something with promises in chains of .then(...).then(...)-s would be a bit frustrating, so we (the javascript community) invented async/await. That way you can write your code like this:
module.exports.getproduct = async (url) => {
let response = await fetch(url);
let body = await response.text();
let $ = cheerio.load(body);
let product = {
productName: $(".product-name").text()
};
console.log(product);
return product;
};
Now it looks a lot nicer, and you can see that the return statement actually is in the right function again! Beware though, you still need not forget to put await before functions that would normally require a .then at the end, but it is definitely easier.
Now you index.js is a little trickier, as you can only use await in a function that is marked with async, but we can:
const {getproduct} = require('./webScraper/getproduct');
let main = async () => {
let product = await getproduct('https://www.americanas.com.br/produto/134118928');
console.log('product:', product);
}
main();
I hope it is a little clearer how you can move forward from here :)
Should add async function wrapper and await promise
// getproduct.js
module.exports.getproduct = url => {
fetch(url)
.then(response => response.text())
.then(body => {
const $ = cheerio.load(body);
const product = {
productName: $(".product-name").text()
};
console.log('getproduct.js > product', product);
return product;
});
};
//index.js updated file
const {getproduct} = require('./webScraper/getproduct');
(async () => {
const product = await getproduct('https://www.americanas.com.br/produto/134118928');
console.log('index.js > product', product);
})();

Categories