Assign variable from fetch returning Promise - javascript

I have two files that are arrays, and i want to load them from a fetch. I have an async function that fetch the files:
async function getData(file) {
const data = await fetch(`./assets/resources/${file}.json`);
return await data.json()
}
Then here is where i assign the variables to the return fo this fetch:
let notes = getData("notes").then(res => res)
let pentagrama = getData("pentagrama").then(res => res)
But with this all i get is:
from google chrome console
How can i actually get the value?

The result of getData is always a Promise that resolves to your data. To access the values, you can use async/await:
(async () => {
let notes = await getData("notes");
let pentagrama = await getData("pentagrama");
// use them here
})();
Alternatively, you can use Promise.all to wait for both promises to resolve, and then access the received data:
let notesP = getData("notes");
let pentagramaP = getData("pentagrama");
Promise.all([noteP, pentagramaP]).then(res => {
let notes = res[0];
let pentagrama = res[1];
// use them here
});

ASYNC
AWAIT
This will work for you if you just want to check the response in your Google Chrome console because in the console you can use await without an async function which probably could be because everything executed in the console is wrapped in an async function by default(just a speculation).
ONLY WORKS IN CONSOLE:
const getData = (file) => (
fetch(`./assets/resources/${file}.json`).then(data => data.json());
)
let notes = await getData("notes")
let pentagrama = await getData("pentagrama")
But if you want to get this working in an application, remember that you ALWAYS need to wrap an await inside async
TO GET IT WORKING IN AN APPLICATION:
const getData = async (file) => (
await fetch(`./assets/resources/${file}.json`).then(data => data.json());
)
const wrapperFunc = async () => {
let notes = await getData("notes")
let pentagrama = await getData("pentagrama")
}

Related

Use fetched API data outside of the function

To make my code cleaner I want to use fetched API data in a few different functions, instead of one big. Even though I 've did manage to reffer to that data in other functions, the problem is the API im a fetching throws different, randomized results every time it is called. And so the output from userData() does not equal that from userData2(), even though my intention is different and I'd like the result variable contents to be the same between functions.
const getData = () =>
fetch("https://opentdb.com/api.php?amount=10").then((response) =>
response.json()
);
const useData = async () => {
const result = await getData();
console.log(result);
};
const useData2 = async () => {
const result = await getData();
console.log(result);
};
Your getData() function returns a promise. One fun fact about promises is that while they can only resolve once, that resolved value can be accessed and used as many times as you want.
const dataPromise = getData();
const useData = async () => {
const result = await dataPromise;
console.log(result);
};
const useData2 = async () => {
const result = await dataPromise;
console.log(result);
};
Using await resolves the promise value, the equivalent of...
dataPromise.then((result) => {
console.log(result);
});
// or `dataPromise.then(console.log)` if you like brevity
I like to point this out about the fetch-api... you should always check the Response.ok property
const getData = async () => {
const res = await fetch("https://opentdb.com/api.php?amount=10");
if (!res.ok) {
throw new Error(`${res.status}: ${await res.text()}`);
}
return res.json();
};

How to return a promise that resolves customized data from API Javascript

So I'm using the API of National Weather Service to create a weather app. But the fetched data is very complicated, and I need to fetch two different APIs. So I want to write a customized async function that returns a promise, which resolves to an object that contains only the necessary data I need.
I came up with something like this:
async function fetchWeatherAPI(){
//data that I need
let data = {};
try {
const res1 = await fetch(url1);
const result1 = await res1.json();
data = {...data , result1.usefulData};
} catch(error){}
try {
const res2 = await fetch(url2);
const result2 = await res2.json();
data = {...data, result2.usefulData};
} catch(error){}
return new Promise((resolve,reject)=>{
resolve(data);
})
}
This code is working for me. But the problem is, what if the APIs reject? How can I handle the error so that I can display the error message in the returned promise? I may want something like this:
return new Promise((resolve,reject)=>{
if(...) reject(errrorMessage);
resolve(data);
})
Just do return data. You're already inside an async function and the return value from that function will be the resolved value of the promise that the async function already returns:
async function fetchWeatherAPI(){
//data that I need
let data = {};
const res1 = await fetch(url1);
const result1 = await res1.json();
data = {...data , result1.usefulData};
const res2 = await fetch(url2);
const result2 = await res2.json();
data = {...data, result2.usefulData};
return data;
}
In addition, your catch blocks are silently eating errors and attempting to continue as if nothing went wrong. You probably just want the error to propagate back to the caller so if you just remove your try/catch blocks, that's what will happen.
And, the return new Promise() you have is entirely superfluous and unnecessary (referred to as an anti-pattern). You can just remove it and return data instead.
Note: Since the code you show does not show any dependency between your first and second fetch() calls, you could run them in parallel and perhaps finish them faster.
async function fetchWeatherAPI(){
//data that I need
let data = {};
const [result1, result2] = await Promise.all([
fetch(url1).then(r => r.json()),
fetch(url2).then(r => r.json())
]);
return {...data, result1.usefulData, result2.usefulData};
}
Or, I often use a helper function in my code when doing a lot of fetch() calls:
function fetchJson(...args) {
return fetch(...args).then(r => r.json());
}
async function fetchWeatherAPI() {
//data that I need
let data = {};
const [result1, result2] = await Promise.all([
fetchJson(url1),
fetchJson(url2)
]);
return { ...data, result1.usefulData, result2.usefulData };
}

Movie API:How Can I Return The Value?

I'm using The Movie Database API. And the problem that i can't solve is returning "keys" variable when i call the function with Movie's id.I'm new on JavaScript that's why i can't solve this. Hope someone can help me, thanks in advance.
const APIURL = "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=[MY API KEY HERE]&page-1";
getMovies(APIURL)
async function getMovies(url)
{
const resp = await fetch(url);
const respData = await resp.json();
showMovies(respData.results)
}
async function getTrailer(id)
{
const resp = await fetch(`https://api.themoviedb.org/3/movie/${id}/videos?api_key=[MY API KEY HERE]&language=en-US`);
const respDataa = await resp.json();
let results = respDataa.results;
let keys = results[0].key;
return keys;
}
function showMovies(movies){
movies.forEach(movie => {
const modals = document.createElement('div');
modals.classList.add('modal');
modals.innerHTML = ` <a target="_blank" href ="https://www.youtube.com/watch?v=${getTrailer(movie.id)}">Watch Trailer</a>`
}
}
Well, first of all, always hide your api keys if you're posting your code somewhere (even if it's a private repository, you shouldn't do it).
Secondly, if you want to return multiple keys, you can map the results to extract id from each of them and do a return:
async function getTrailer(id)
{
const resp = await fetch(`https://api.themoviedb.org/3/movie/${id}/videos?api_key=04c35731a5ee918f014970082a0088b1&language=en-US`);
const respDataa = await resp.json();
let results = respDataa.results;
return results.map(({ key }) => key);
}
Async functions return a Promise in JavaScript.
Simply add return keys at the end of your function.
Then you can do:
getTrailer(528085).then(data => {
// do something with the data
})
You can also handle errors:
getTrailer(528085)
.then(data => {
// do something with the data
})
.catch(err => {
/*
An error occured. You can use err.toString() to convert the error into a string
*/
})
If you want to get the returned data immediately from an async function(or a promise), put your logic inside an async function, then you can simply do:
let keys = await getTrailer(528085)
And, here is how to handle errors in async/await:
try {
let keys = await getTrailer(528085)
}
catch(err){
/*
An error occured. You can use err.toString() to convert the error into a string
*/
}
By the way, like Desiigner said, don't keep your API keys in the client. Anyone can see your API key. Use a server to return the API response to the client.
We have to await or.then the return (it’s a Promise).
function showMovies(movies) {
// make the forEach callback async
movies.forEach(async (movie) => {
console.log(getTrailer(movie.id)) // Promise {<pending>}
const trailer = await getTrailer(movie.id);
console.log({ trailer });
const modals = document.createElement("div");
modals.classList.add("modal");
modals.innerHTML = ` <a target="_blank" href ="https://www.youtube.com/watch?v=${trailer}">Watch Trailer</a>`;
});
}

React Multiple Fetch Requests

I am making 2 fetch requests. I want to convert the data to JSON and then set it to a variable.
async componentDidMount() {
Promise.all([
await fetch('/link1'),
await fetch('/link2'),
]).then(links => {
const response1 = links[0]
const response2 = links[1]
const res1 = response1.json()
const res2 = response2.json()
})
const data1 = res1.data
const data2 = res2.data
...
I'm not able to set data1 and data2 to the responses. I am new to this so I'm not sure how to format it. How do I set data1 and data2?
You can just do
let data = [];
Promise.all([fetch("/link1"), fetch("/link2")])
.then(responses =>
responses.forEach(res => res.json().then(body => data.push(body)))
)
.catch(err => console.error(err));
If you need access to those variables under render, it is common to store them in a state variable.
async componentDidMount() {
Promise.all([
await fetch('/link1'),
await fetch('/link2'),
]).then(links => {
const response1 = links[0]
const response2 = links[1]
const res1 = response1.json()
const res2 = response2.json()
this.setState({data1: res1.data, data2: res2.data})
})
Then use you can use data1 and data2 as this.state.data1/2
To understand why what you are doing is not working, you need to read more about how Promise works. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
The main reason is because JS is async, so the data1 and data2 are assigned at the same time as Promise.all is fired.
Here's how I would do multiple fetches.
Promise.all(
[
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2'
].map(url => fetch(url).then(r => r.json()))
).then(results => console.log(results))
Promise.all takes an array of promises and returns a new promise that is complete when all the provided promises have completed.
It's best to do the .json() work in the thenable chain (since the conversion to JSON is asynchronous as well as the fetch). And then just await the two final results.
The result of the Promise.all is an array of the results of each promise (in the same order you provided the promises to Promise.all -- doesn't matter which order they completed in.)
Don't use await and Promise both. You can try like this to get the expected output.
async componentDidMount() {
const link1Fetch = await fetch('/link1');
const link2Fetch = await fetch('/link2');
const data1 = await link1Fetch.json();
const data2 = await link2Fetch.json();
console.log(data1, data2);
}

ES8 using arrow function with async and await

I'm currently learning how to use ES8's fetch, async and await I currently have this code that works:
const url = "https://api.icndb.com/jokes/random";
async function tellJoke() {
let data = await (await fetch(url)).json();
return data.value.joke;
}
tellJoke().then(data => console.log(data));
Console:
"Chuck Norris can dereference NULL."
but I found a snippet using an arrow function, the problem is that I don't know how to return my value the way I'm doing it in my current example.
SNIPPET:
const fetchAsync = async () =>
await (await fetch(url)).json()
If this is not a best practice let me know, also any further reading is welcomed.
You can again use the same approach that you used to shorten the usual
async function tellJoke() {
let response = await fetch(url);
let data = await response.json();
return data.value.joke;
}
to your implementation. As a one-liner it can look like this:
const tellJoke = async () => (await (await fetch(url)).json()).value.joke;
Use as same in the function. If you have no body expression in your code (witout {}), it will return the result of the statement. In this case the result of await (await fetch(url)).json().value.joke.
const fetchAsync = async () => (await (await fetch(url)).json()).value.joke;
or with multi line body. With body expression {} you need explicitly return as in simple function.
const fetchAsync = async () => {
const result = await fetch(url);
const data = await result.json();
return data.value.joke;
}

Categories

Resources