making api requests and response.json() - javascript

I have a question about api request and async await
For example, I have a function as such:
export const getTopStories = async () => {
const response = await instance.get(`/home.json?api-key=${api_key}`)
const data = response.json()
return data
}
is response.json() completely necessary here? I think I've also seen it where data is destructured immediately, for example,
export const getTopStories = async () => {
const {data} = await instance.get(`/home.json?api-key=${api_key}`)
return data
}
Does the second version work? Are they equivalent somehow?

Related

how to get only data from fetch [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 months ago.
I try to get only the data of my fetch request but when i go out of my function there is a promise arround.
I try to fetch an API for starting a store in svelteJS but I'm wrong.
import {writable} from "svelte/store";
const getPokedex = async function () {
let pokedexData
await fetch('https://pokeapi.co/api/v2/pokemon?limit=100&offset=0')
.then(response => response.json())
.then(data => {
pokedexData = createPokedex(data)
})
return pokedexData
}
const createPokedex = function (data) {
let pokedex = writable(data)
...
}
export const pokedex = getPokedex();
SOLVED:
const getPokedex = async () => {
const response = await fetch('https://pokeapi.co/api/v2/pokemon?limit=100&offset=0');
const data = await response.json();
let pokedex = data.results
return createPokedex(pokedex);
}
export const pokedexStore = await getPokedex();
Make use of async/await and try to not use then/catch while using async/await this will make your code more clean, readable, easy to work with
const getPokedex = async function () {
const response = await fetch("https://pokeapi.co/api/v2/pokemon?limit=100&offset=0");
const data = await response.json();
return createPokedex(data);
};
this code will return the data you just have to wait for the promise using await
const pokedex = await getPokedex();

How to guarantee that data from 'fetch' is present

I am doing something like this, where I retrieve the data of a fund which contains an id, then I query the server again using the retrieved id to retrieve data from another table:
const [backendData, setBackendData] = useState({})
const [fundData, setFundData] = useState({})
useEffect(() => {
async function fetchFund(){
console.log("fetching fund...");
var query = getQueryVariable('fund');
await fetch(`http://localhost:24424/api/funds?fund=${query}`).then(
response => response.json()
).then(
data =>{
setBackendData(data);
}
)
}
async function fetchData(){
var fundId = backendData[0]?._id ?? "fundid";
await fetch(`http://localhost:24424/api/funds/data?id=${fundId}`).then(
response => response.json()
).then(
data =>{
setFundData(data);
}
)
}
fetchFund();
fetchData();
}, [])
The problem is that in the fetchData() function, fundId is always equal to the fallback value fundid when the page first loads, so the server query fails. When using {fundId} later on in the page, it works fine as the value is eventually retrieved. How can I tell React to wait for backendData[0]?._id to be present before executing the fetchData() function?
You should separate the two function so one depend of the existing of the other your code will look something like this
const [backendData, setBackendData] = useState({})
const [fundData, setFundData] = useState({})
useEffect(() => {
async function fetchFund(){
console.log("fetching fund...");
var query = getQueryVariable('fund');
await fetch(`http://localhost:24424/api/funds?fund=${query}`).then(
response => response.json()
).then(
data =>{
setBackendData(data);
}
)
}
fetchFund();
}, [])
useEffect(() => {
if(!backendData?.[0]?._id) return;
async function fetchData(){
var fundId = backendData[0]?._id ?? "fundid";
await fetch(`http://localhost:24424/api/funds/data?id=${fundId}`).then(
response => response.json()
).then(
data =>{
setFundData(data);
}
)
}
fetchData();
}, [backendData])
Now fetchData will only get called when at least one backendData is available

How to escape this callback hell

I'm currently trying to fetch data from public API about a country and its neighboring countries to render on my html.
renderCountry( ) is a function to implement on my html with the data I will receive.
I also excluded some unnecessary codes, which I believe is not major in this particular case.
This is how I fetch data:
const getCountryAndNeighbour = function(country) {
fetch(`https://restcountries.com/v2/name/${country}`)
.then(response => response.json())
.then(data => {
renderCountry(data[0]);
const neighbour = data[0].borders;
neighbour.forEach(country => {
fetch(`https://restcountries.com/v2/alpha/${country}`)
.then(response => response.json())
.then(data => renderCountry(data, `neighbour`))
});
})
}
Here, you will see callback hell architecture. Any idea for escape from that?
Thanks in advance.
You can try using async/await. You would add async before the function keyword and add await as needed. See below to see this in action:
const getCountryAndNeighbour = async function (country) {
const res = await fetch(`https://restcountries.com/v2/name/${country}`)
const data = await res.json();
renderCountry(data[0]);
const neighbour = data[0].borders;
await Promise.all(
neighbour.map(async country => {
let response = await fetch(`https://restcountries.com/v2/alpha/${country}`)
response = await response.json();
return renderCountry(response, 'neighbour');
});
);
}
You can rewrite it using async/await
eg.
const getCountryAndNeighbour = async country => {
const response = await fetch(`https://restcountries.com/v2/name/${country}`);
const data = await response.json();
renderCountry(data[0]);
const neighbour = data[0].borders;
neighbour.forEach(async country => {
const response = await fetch(`https://restcountries.com/v2/alpha/${country}`)
const data = await response.json();
renderCountry(data, `neighbour`);
});
};
Please note that forEach will run all promises in the same time.
If you want to run one by one you should use eg. for loop or some util like Bluebird.map which allows you to specify a concurrency
Good luck!
This will do using Async/await
async function getCountryData(country) {
const response = await fetch(`https://restcountries.com/v2/name/${country}`);
return await response.json();
}
async function getNeighbourData(country) {
const response = await fetch(`https://restcountries.com/v2/alpha/${country}`);
return await response.json();
}
async function getCountryAndNeighbour(country) {
const data = await getCountryData(country);
const neighbourCountries = data[1].borders;
for (const neighbour of neighbourCountries) {
const response = await getNeighbourData(neighbour);
console.log(response);
}
}
Add the necessary validations when checking [0]/[1] in your function.

How can I call async function inside a loop?

I have below code in node. In getPosts, it reads 10 posts from database which is an async function call. And for each post, it needs to read user info. from database which is another async function call. How can I make it work in node js?
const getUser = async (userId) => {
// read user from database
}
const getPosts =async () => {
const posts = await getPostsFromDB(10); // get 10 posts from database
for(let i=0; i<posts.length; i++){
posts[i].user = await getUser(posts[i].userId) // ERROR: I can't call await inside a loop
}
}
I am thinking about using Promise.all() like below:
const getPosts =async () => {
const posts = await getPostsFromDB(10); // get 10 posts from database
const allProms = posts.map(post => getUser(post.userId));
Promise.all(allProms); // how can I assign each user to each post?
}
but I don't know how I can assign each user to each post after calling Promise.all().
Consider approaching the problem slightly differently. If you wait for responses in an iterative loop, it'll produce poor performance. Instead, you could push them all into an array and wait for them — so they're all fetching at the same time.
const getUser = async (userId) => {
try {
// read
} catch (e) {
// catch errors
}
// return data
}
const getPosts = async () => {
const posts = await getPostsFromDB(10); // get 10 posts from database
const userRequests = posts.map((post, index) => getUser(post.userId))
const users = await Promise.all(userRequests)
return posts.map((post, index) => {
post.user = users[index]
})
}
If you think you may have duplicate userIds, consider forming a list of users you can reference before calling getUser.

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.

Categories