Why `response.json().<key>` returns unidentified value - javascript

I'm trying to fetch a json file the api in the code below ,When I convert the json response to a javascript object I expect to be able to access the value of the key results in that object which is an array but when i log the response in the second then chain i get unidentified
const URLS = "https://pokeapi.co/api/v2/pokemon?limit=1000"
fetch(URLS)
.then(response => {
return response.json().results
})
.then((pokemons) => {
console.log(typeof pokemons)
});
When I changed the code to this
const URLS = "https://pokeapi.co/api/v2/pokemon?limit=1000"
fetch(URLS)
.then(response => {
return response.json()
})
.then((pokemons) => {
console.log(typeof pokemons.results)
});
it seems working fine but i don't understand why this problem is happening

response.json() returns a Promise resolving to the result of parsing the text of the response as JSON. You cannot directly access properties on that result without awaiting the Promise with .then or await in an async function.

Related

Javascript JSON Fetch with await returns data but its function return an empty array

I'm trying to fiddle with fetching data from public APIs and then showing that data in a React component, the react part is not important tho, this is primarly a js issue. I'm using PokeApi for learning purpose, I create a new object with the data I need from the request, and then push that object to an array that the function returns when called:
// fetchPoke() function
let pokemons = []
// IDs is just an array with 20 random numbers between a range
IDs.forEach(async (id) => {
let url = `https://pokeapi.co/api/v2/pokemon/${id}`
await fetch(url)
.then((res) => {
if (!res.ok) {
console.log(`${id} not found`)
} else {
return res.json()
}
})
.then((data) => {
let pokemon = {}
pokemon.id = data.id
pokemon.name = data.name
pokemon.image = data.sprites.other.dream_world.front_default
pokemons.push(pokemon)
})
})
// function returns the array of object
return pokemons
But whenever I call this function
let pokemons = fetchPoke()
And then log it
console.log(pokemons)
Although I can see the content, it says it's an array of 0:
In fact if I try to console log pokemons.length I get 0
What could cause this? Am I doing something wrong in my fetch request?
So, you create an empty array.
You loop through you loop through the array, firing-off a bunch of asynchronous requests that will, as a side-effect, populate the empty array when the promises complete.
You immediately return the array without waiting for the promises to complete.
The requests probably have not even left your machine by the time this happens.
The array is empty at this point.
If instead, you declare your function as async and you map your IDs to a new array of promises, then await them all with Promise.all, then the promises will be able to complete before the function returns, and the resolved value of Promise.all will be an array containing your pokemons.
async function getSomePokemons(IDs) { // note, this is an async function
const promises = IDs.map((id) =>
fetch(`https://pokeapi.co/api/v2/pokemon/${id}`)
.then((res) => {
if (!res.ok) {
console.log(`${id} not found`)
// implicitly resolves as undefined
} else {
return res.json()
}
})
.then((data) => (data ? { // data might be undefined
id: data.id,
name: data.name,
image: data.sprites.other.dream_world.front_default
} : undefined))
)
const pokemons = await Promise.all(promises);
return pokemons;
}

How can I return multiple function values in a single array

I am crawling 5 different sites for data using node-fetch and cheerio.
everything checks out but I need to collect the returned data from these 5 separate functions in an array.
First I store function name and url for each site in an object like so
url: 'https://sampleurl.com',
crawl: FirstLinkCrawl
}
const secondLink = {
url: 'https://sampleurl.com',
crawl: secondLinkCrawl
}
}```
Then I write the function to crawl each site like so, I ran this function with and without promise, both check out
```const secondLinkCrawl = (body) =>{
return new Promise((res, rej)=>{
"this crawl function is ran here, everything works fine, Data is an object"
const error = false
if(!error){
res(Data)
}else{
rej()
}
})
}```
This here is my fetch function that takes the url and a callback, which is the crawl function
```async function Fetch(url, callback){
const response = await fetch(url)
const html = await response.text()
callback(html)
}
Then I call the fetch and crawl using promise.all() in an attempt to have it return in an array, but in an array,
const promises = [
Fetch(firstLink.url, firstLink.crawl),
Fetch(secondLink.url, secondLink.crawl)]
Promise.all(promises)
.then(values => console.log(values))
.catch(err => console.log(err))
}
When I run this, I get [ undefined, undefined ]
But when I run it without promises and simply log the result, both of them run successfully.
My aim is to get my results in a single array. what can I do?
I also tried declaring an array a the top of the page and then pushing each result into the array, after which I log the array at the bottom of the functions call. But the array returns empty
You're not returning anything from Fetch function that's why it's undefined. You can fix it by -
async function Fetch(url, callback){
const response = await fetch(url)
const html = await response.text()
const result = await callback(html);
return result;
}
As the callback, you are passing in Fetch function returns Promise so we can await it and return the result

Javascript Promises: fetch .then retrieving [[PromiseValue]]

I'm trying to retrieve the [[PromiseValue]] of a Promise.
My function currently returns a Promise instead and the value I want myFunction to return is the value stored in [[PromiseValue]] of the returned Promise.
This returns a Promise.
myFunction(){
return fetch("/api")
.then(res => {
return res.json();
})
.then(json => {
return json;
})
}
I tried this code, but when I print the data in console, it prints the correct value, but the returned value is undefined.
myFunction(){
return fetch("/api")
.then(res => {
return res.json();
})
.then(json => {
return json;
})
.then(data => {
const stringData = data.toString();
console.log(stringData); // prints the correct string
return stringData; // returns undefined
})
}
How would I make my function return the value stored in [[PromiseValue]] as a String?
Please help me out, thanks!
Your function cannot return the PromiseValue directly, since fetch works asynchronously. It will return a Promise which will eventually resolve to that value.
Using async/await, what you could do is:
async function myFunction() {
const res = await fetch('/api');
const json = await res.json();
return JSON.stringify(json);
// json.toString() is a bit weird … but do as you please
// I'd return the json and parse it at the callsite.
}
const result = await myFunction();
(note: this snippet requires a modern engine which supports top-level await. Latest chrome will work just fine.)

API returning data in a promise but can't be transitioned into a string [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm trying to get the items of an external API and although the results are showing in the console, I'm having some trouble trying to pull the data and interpret it into a HTML output.
I create a const called makeRequest for example which pulls data from the API when I try to convert it to a string or use innerHTML to pull into a class, I get either "object promise" or undefined.
I'm stumped. Any ideas? I'm sure I'm missing something obvious but I haven't been practising JS for long.
EDIT: I'm able to return the data to the console log but I'm unable to get that response to become a string and parse into HTML
https://codepen.io/iambeeroy/pen/dKJjQw
//Request is defined and
const request = options => {
return fetch(options)
.then((response) => {
return response.json();
})
.then((data) => {
return data;
})
.catch(error => console.error(error));
};
//Logs the request in the console
const makeRequest = request('https://api.punkapi.com/v2/beers?abv_gt=6');
console.log(makeRequest);
var res = makeRequest.toString();
document.getElementById("beers").innerHTML = res;
This isn't how promises work. The bits inside the then() and catch() callbacks execute after the rest of the code. So your makeRequest variable will be a Promise object, and you can't convert it into a string. It's not actually data, it's a promise to deliver data at some point in the future.
Anything that you want to do with the promised data has to be done inside callbacks, like this:
//Request is defined and
const request = options => {
return fetch(options)
.then((response) => {
//this gets passed on to other .then() calls
return response.json();
})
.catch(error => console.error(error));
};
const makeRequest = request('https://api.punkapi.com/v2/beers?abv_gt=6')
.then(data => {
//this will get the response.json() result from the fetch callback above
var res = data.toString();
document.getElementById("beers").innerHTML = res;
});

Axios AJAX call in React returning only initial state

I'm trying to make a simple AJAX call using Axios in React, but I can't figure out where I'm going wrong.
Here is what I have so far (within my component):
ComponentDidMount() {
axios.get('https://jsonplaceholder.typicode.com/users')
.then( res => {
const users = res
this.setState({ users });
});
}
render() {
console.log(this.state.users) // returns the **initialised EMPTY array**
return (
<div>
{this.state.users.map( user => <p>{user.name}</p>)} // returns nothing
</div>
)
}
I am accessing a simple array at the URL given in the .get() method (check it out to see it's structure if necessary). I then chain on the .then() promise and pass the res argument in an arrow function.
Then I assign the users variable to the result, and attempt to set the state as this. So at this point I'm expecting this.state.users to equal the resulting array.
However...
A) When I try console.log(this.state.users), it returns the initialised empty array
B) When I try to render a map of the array, iterating through the name property on each object, again, nothing.
Where am I going wrong?
A part from the typo (as Phi Nguyen noted), a few other things to fix:
1) Axios resolves the promise with a response object. So to get the results you need to do:
axios.get('https://jsonplaceholder.typicode.com/users')
.then( res => {
const users = res.data; // Assuming the response body contains the array
this.setState({ users });
});
Check out the docs about the response object here: https://github.com/mzabriskie/axios#response-schema
2) If there's an exception (your request fails) you probably want to handle it instead of swallowing it. So:
axios.get('https://jsonplaceholder.typicode.com/users')
.then( res => {
const users = res.data; // Assuming the response body contains the array
this.setState({ users });
})
.catch(err => {
// Handle the error here. E.g. use this.setState() to display an error msg.
})
typo. It should be componentDidMount instead of ComponentDidMount.

Categories

Resources