Javascript Fetch and Map not working correctly - javascript

I'm trying to fetch a multiple page api and place the json within an array. I've set it up so it does the required number of fetches and is setting up the correct number of promises. I am getting 50+ different responses. However, when I try to map each of those responses, it only pulls the first set of data and pushes that repetitively to the array. What am I not doing correctly?
var data;
fetch(URL_ARTISTS3,{
method:'GET'
})
.then(response => response.json())
.then(json => {
data =json;
const apiPromises = [];
var pagesRequired = Math.ceil(json.setlists["#total"] / json.setlists["#itemsPerPage"]);
for (let i=pagesRequired; i>0;i--) {
var fetchurl = URL_ARTISTS3 + '?page = ' + i;
apiPromises.push(fetch(fetchurl, {
method: "GET",
body: json
}));
}
Promise.all(apiPromises)
.then(responses => {
var processedResponses = [];
responses.map(response => response.json()
.then(json => {
/****THIS LINE ADDS THE SAME JSON RESPONSE MULTIPLE TIMES*****/
processedResponses.push(json.setlists.setlist);
})
)
console.log('processedResponses: ', processedResponses)
});

I'm not sure it solves the problem, but one issue is that you are logging processedResponses before the promises are resolved.
You can simplify your code a lot by moving the response.json() call:
apiPromises.push(
fetch(fetchurl, {method: "GET", body: json})
.then(response => response.json())
.then(json => json.setlists.setlist);
);
// ...
Promise.all(apiPromises).then(processedResponses => console.log(processedResponses));

Related

How do I type a Response object from a fetch request?

I'm running parallel requests for a series of fetches. I want to type results as an array of response objects (instead of array of type any) but I'm unsure of how to do this. I googled "how to type response object in Typescript" but didn't get useful hits. Is there a way to type the response object other than manually creating a custom type that has all the properties on a response object? Does Typescript have a special built in type we could use here?
const results: any = [];
fetch(URL, {
headers: {
...
}
})
.then(response => {
results.push(response);
})
.catch(err => {
...
})
const responses = await Promise.all(results);
return responses;
Since I am using node-fetch, I ended up with the following solution.
https://www.npmjs.com/package/node-fetch#class-response
import { Response } from 'node-fetch';
const results: Response[] = [];
fetch(URL, {
headers: {
...
}
})
.then(response => {
results.push(response);
})
.catch(err => {
...
})
const responses = await Promise.all(results);
return responses;

Get Cart Id from JSON response

I need to capture the cartID in a js variable from a JSON response.
So far I have the following code which requests the cart information.
function getCart(url) {
return fetch(url, {
method: "GET",
credentials: "same-origin"
})
.then(response => response.json())
};
var cartID = 'unknown';
getCart('/api/storefront/carts')
.then(data => console.log(JSON.stringify(data)))
.catch(error => console.error(error));
The console.log data is formatted like this:
Extract of full data:
[{"id":"c5f24d63-cd9a-46f2-be41-6ad31fc38b51","customerId":1,"email":"me#gmail.com", ................. }]
I have tried various methods to capture the cart ID to variable cartID, but each time it shows 'unknown' and is logged before the data response.
Any ideas how to delay until the response is ready and then 'cartID' with the id value?
Because the response if a JSON array, you can try to loop and extract the cartID from each cart object:
function getCart(url) {
return fetch(url, {
method: "GET",
credentials: "same-origin"
})
.then(response => response.json())
};
var cartID = 'unknown';
getCart('/api/storefront/carts')
.then(
data => {
//The response is an array of cart objects. We need to extract the ID from the array
cartID = data[0].id;
//Or loop through the response and extract the ID from each cart object
for (var i = 0; i < data.length; i++) {
cartID = data[i].id;
}
}
)
.catch(error => console.error(error));

How to send session cookies in a fetch request?

In python I wrote some code that allows me to fetch data by sending the session cookies:
import requests
url = "https://fantasy.espn.com/apis/v3/games/ffl/seasons/2021/segments/0/leagues/1662510081?view=mRoster"
print(url)
r = requests.get(url,
cookies={'swid': '{A1cFeg47WrVdsREQZNAo}',
'espn_s2': 'AWDB51sqnG8dsc3wfdsffsd'})
d = r.json()
d
I wanted to implement this in javascript so I wrote:
let leagueId = 1662510081;
let endpoint = "mRoster";
let url =
"https://fantasy.espn.com/apis/v3/games/ffl/seasons/2021/segments/0/leagues/" +
leagueId +
"?view=" +
endpoint;
console.log(url);
let playerList = [];
fetch(url)
.then((response) => response.json())
.then((data) => {
console.log(data)
});
How can I implement the cookies in the fetch request? I tried set-cookies in the headers but that didn't end up working.
Because your question tags nodejs, I'm assuming you are using node-fetch;
Apparently, there isn't any explicit way to send cookies, except using the headers method. So, you can use this code.
let fetch = require('node-fetch'); // or import fetch from 'node-fetch';
let leagueId = 1662510081;
let endpoint = "mRoster";
let url =
"https://fantasy.espn.com/apis/v3/games/ffl/seasons/2021/segments/0/leagues/" +
leagueId +
"?view=" +
endpoint;
console.log(url);
let playerList = [];
fetch(url, {
headers: {
cookie: "test=test"
}
})
.then((response) => response.json())
.then((data) => {
console.log(data)
}); // node-fetch
Also, browser/vanillaJS method:
...
fetch(url, {
credentials: 'include'
})
.then((response) => response.json())
.then((data) => {
console.log(data)
}); // browser/vanillaJS

Getting .json is not a function on Promise.all w/fetch

Oh once again I have those Promise.all blues:( I have a function that makes an array of fetch call's from provided urls and then we want to retrieve data via a Promise.all and return array of reponses or better yet just return the promise to calling function. . The problem is this results in error w/console showing:
There was problem retrieving data. TypeError: r.json is not a function
The code for the function is :
const getLeagueLeaders = (url, params) => {
// First let's create the array of url's
let queryURLs = [];
params.forEach((param) => {
queryURLs.push(
fetch(`${url}${new URLSearchParams(param)}`, {
method: "get",
headers: {
Authorization:
"Basic ==",
},
}).then((res) => res.json())
);
});
return (
Promise.all(queryURLs)
// map array of responses into an array of response.json() to read their content
.then((responses) => responses.map((r) => r.json()))
.catch((err) => {
console.error("There was problem retrieving data.", err);
})
);
};
module.exports = getLeagueLeaders;
And in Vue component
mounted: async function () {
const leagueLeadersResponseArray = await getLeagueLeaders(
this.fetchBaseUrl,
this.params
);
this.qbLeaders =
leagueLeadersResponseArray[0].cumulativeplayerstats.playerstatsentry;
Obviously leagueLeadersResponseArray is undefined. I researched .json() and dont see how I am using it incorrectly. At first i thought I needed a Promise.all wrapper for the responses.map((r) => r.json()) but that did no good either. I looked at this link but I am not using fetch as he is. Any guidance much appreciated....
Updated working code for anybody else:
// ---------- src/js/modules/ ------------------ //
/* jshint ignore:start */
// Make function to retrieve League Leaders in a Category
const getLeagueLeaders = (url, params) => {
// First let's create the array of url's
let queryURLs = [];
params.forEach((param) => {
queryURLs.push(
fetch(`${url}${new URLSearchParams(param)}`, {
method: "get",
headers: {
Authorization:
"Basic ==",
},
}).then((res) => res.json())
);
});
return Promise.all(queryURLs).catch((err) => {
console.error("There was problem retrieving data.", err);
});
};
module.exports = getLeagueLeaders;
Your template string is around the entire fetch when it should only be in the argument to fetch:
params.forEach((param) => {
queryURLs.push(fetch(`${url}${new URLSearchParams(param)}`, {
method: "get",
headers: {
Authorization:
"Basic *****==",
}
}));
});
Then, you have a .then(data => {return data}), which doesn't do anything since the return returns from the then callback, not the function. You should instead return the promise that Promise.all gives you:
return Promise.all(queryURLs)
// map array of responses into an array of response.json() to read their content
.then((responses) => responses.map((r) => r.json())) // Get error There was problem retrieving data. TypeError: r.json is not a function
.catch((err) => {
console.error("There was problem retrieving data.", err);
});

Multiple API Calls in React

I am making an app where I receive data from an API. Once I get this data I want to make another call to the same API with the endpoint that I got from the first call.
fetch(req)
.then((response)=>(
response.json()
)).then((json)=>{
console.log(json)
json.meals.map((obj)=>{
let url = `https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/${obj.id}/information`
let req = new Request(url,{
method: 'GET',
headers: header
})
fetch(req)
.then((response)=>(
response.json()
)).then((json)=>{
console.log(json);
this.setState((prevState)=>{
recipe: prevState.recipe.push(json)
})
})
})
this.setState(()=>{
return{
data: json
}
})
})
I am making two fetch requests here but the problem is the data from the first response is output after second fetch request. Also the state: data gets set before state: recipe and the components render with the data from state: data.
render(){
return(
<div className="my-container">
<EnterCalorie getData={this.getData}/>
<MealData data={this.state.data} recipe={this.state.recipe}/>
</div>
)
}
How can i make sure both get passed down at the same time?
In line 3 return return response.json() instead of nothing (undefined).
Update:
const toJson = response => response.json()
fetch(req)
.then(toJson)
.then(json => {
this.setState(() => {
return {
data: json
}
})
return json
})
.then((json) => {
console.log(json)
const promises = json.meals.map((obj) => {
let url = `https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/${obj.id}/information`
let req = new Request(url, {
method: 'GET',
headers: header
})
return fetch(req)
.then(toJson)
.then((json) => {
console.log(json);
this.setState((prevState) => ({
recipe: prevState.recipe.push(json)
}))
})
})
return Promise.all(promises)
})
.then(() => {
console.log('job done')
})
You need to map your array into promises. Then use Promise.all to wait for them the get resolved.
There was parenthesis missing from:
this.setState((prevState)=>{
recipe: prevState.recipe.push(json)
})
A sidenote, this whole stuff should be refactored. You're not going to get far with this code style / code complexity.
fetch(req) // req no1
.then((response)=>(
response.json()
)).then((json)=>{
console.log(json)
json.meals.map((obj)=>{
let url = `https://spoonacular-recipe-food-nutrition-v1.p.mashape.com/recipes/${obj.id}/information`
let req = new Request(url,{
method: 'GET',
headers: header
})
fetch(req) // req no 1 called again
.then((response)=>(
response.json()
)).then((json1)=>{
console.log(json1);
this.setState((prevState)=>{
recipe: prevState.recipe.push(json1)
})
this.setState(()=>{
return{
data: json
})
})
})
})
})
I think you are calling api with same req parameters again in the second fetch call
This is a callback hell, please look for Promise races, and check the all() promise method.

Categories