Catching part of a JSON response and saving into a variable? - javascript

I have a question I've spent the past few days with my friend google trying to answer. This is the code from a project I'm currently working on and I'm trying to interface with two API's.
What you see here is a call to the first API using the GOT library formatting to receive a JSON response.
var products
//Printify call for products list
(async () => {
try{
const list = await redd('shops/shopId/products.json');
//Catch the Data array and save it into the variable products
var obj = new JSONObject(response);
products = obj.getJSONArray("data");
}
catch(error) {
}
})();
//Print the variable products to the console
console.log(products)
I create a new JSONObject from the response and grab the Data Array from that response and put it in the Variable products which was defined outside this function. Finally I'm trying to print the variable to the console.
Eventually I will need to take that "data" Array and parse for specific items inside it (i.e. title: , description: , images:) and pass it as a value into the next API.
Currently I'm getting a "undefined" response from the console. Not sure what I'm doing wrong, hoping that I can get some help or direction. Anything is appreciated, thank you all in advance!

I was finally able to get it all working. It's actually been a minute since I solved, but wanted to make sure it worked. Here is the final code that ended up working for me:
//Config for a new GOT instance, to use redd as the variable with the attached headers and options
const redd = got.extend({
prefixUrl: 'https://api.printify.com/v1',
responseType: 'json',
headers: {
'Authorization': 'Bearer ' + apiKey
}
});
var productsParsed //Setting up global variable to accept the array from the JSON response body
//Printify call for products list
getProducts = async () => {
try{
const response = await redd('shops/' + shopId + '/products.json');
productsParsed = response.body.data; //Data is the array in the body I need access to, and saving that into the var productsParsed
//Returning the var with the new value
return productsParsed
}
catch(error) {
console.log(error.response);
}
};
getProducts().then(console.log); //Printing the return value from getProducts() which verifies the var contains the needed value
So the solution ended up being fairly simple. I just didn't fully understand the GOT structure. I had to use dot notation to pin down my return statement. After figuring that out I was able to use my global variable that I had set up to accept the value of the JSON response body. Thank you all for your suggestions and assistance. I hope this post is able to help any others in a similar situation to myself.

You've defined an async function, but you haven't awaited its result.
I think adding await in front of the call site would fix that.

Because it's an async function the console.log is called before the async function is finished. Move it inside the async function and it should work.
var products
//Printify call for products list
(async () => {
try{
const list = await redd('shops/shopId/products.json'); // we wait for the response here
//Catch the Data array and save it into the variable products
var obj = new JSONObject(response);
products = obj.getJSONArray("data");
//Print the variable products to the console will work here
console.log(products)
}
catch(error) {
}
})();

Related

Seeking proper way to use the get() method of INDEXEDDB data store

I am attempting to use a simple indexeddb 'get' method to retrieve a keyed record from an existing data store. For some reason that i have been unable to find, though the result of my 'get' request is 'successful', the returned value is 'undefined'.
The code below is called from an event listener that is fired when the user clicks on a button in a row of a table, indicating the user wants details on that particular row. Each row in the table represents a record in the indexeddb data store that has already been created. There are 8 values of interest in each row, but only 3 are displayed in my html table. I am simply attempting to access the row in the data store to get all 8 values in order to pass them along to the next process.
The following code is called from an event listener created on a 'Select' button for each row...
async function getGameInProgressDetails(gameID) {
try {
db = await idbConnect(DBName,DBVersion);
let tx = db.transaction(['gamesList'], 'readonly');
let gameStore = tx.objectStore('gamesList');
// I have confirmed the 'gameID' passed in is the key value that i would expect
// to retrieve the desired result.
let req = gameStore.get(gameID); // gameID comes from the selected row in the html table.
req.onsuccess = (ev) => {
console.log('Success');
let request = ev.target;
console.log(request); // returns an IDBRequest object with result: undefined and error: null.
let theGame = request.result;
console.log(theGame ); // displays 'undefined'.
}
req.onerror = (err) => {
console.warn(err);
};
} catch (e) {
console.warn(e);
}
I get the 'success' message indicating that the 'get' operation was successful, but my result is 'undefined'. Could someone please tell me if i am missing a step or if there's another way to go about this that i should look into? I've looked at a variety of tutorials and i must be overlooking something 'obvious'.
I discovered the problem with my code/approach and am answering my own question. The reason that the above code was not working was not because of my indexeddb code or logic at all.
What i discovered was that the index value that i had passed into the routine needed to be cast as an integer before the get() method call, JS was treating it as a string value. I was confused by the fact that i had checked the value in a console.log statement and it had shown the appropriate value. What i hadn't considered was how JS evaluated what type the variable value was.
For those coming later and seeing this, my final code was thus:
async function getGameInProgressDetails(gameID) {
db = await idbConnect(DBName,DBVersion);
let tx = db.transaction(['gamesList'], 'readonly');
var gameStore = tx.objectStore('gamesList');
let gameIndex = gameStore.index("gameIDIdx");
let request = gameIndex.get(parseInt(gameID)); //!! NOTE THE parseInt!!
request.onsuccess = function() {
if (request.result !== undefined) {
console.log("Games", request.result);
} else {
console.log("No such games.");
}
}

Messy order on items fetched

I'm trying to display 10 pokemons on the html... What I'm getting sometimes is a messy order on the final result. Like pokemon with id=5 appears 2nd and so on .
I assume my error comes from some asynchronism between the functions calls.
I'm kinda new on async functions so don't judge me bad on it lol...
So my code goes like this:
pokemonAPI = "https://pokeapi.co/api/v2/pokemon?offset=0&limit=10";
async function getPokemonList(url){
let resp = await fetch(url);
if (resp.ok){
let list = await resp.json();
list.results.forEach(pokemon => {
getPokemonData(pokemon.url);
});
}
}
Then getPokemonData function:
async function getPokemonData (url){
let resp = await fetch(url);
if (!resp.ok){
throw new Error(`HTTP error!, fetching pokemon data. Status: ${resp.status}`);
}
let data = await resp.json();
fillContent(data);
}
fillContent function uses innerHTML to add a new card to my container div element.
Finally the result (not always) looks like this: Display error
Any suggestions on where I'm getting it wrong?
Thanks to #A_A for the help
Nvm the first comment, I was a bit confused. A simple for loop instead
of forEach and await getPokemonData(pokemon.url) should do the trick
So actually I was calling my function getPokemonData(pokemon.url) one after another in a forEach without waiting for it to finish fetching the url I was sending.
for (let pokemon of list.results){
await getPokemonData(pokemon.url);
}
Changing it to a simple loop and waiting for my function to end solved it

How to use Promise.all with multiple Firestore queries

I know there are similar questions to this on stack overflow but thus far none have been able to help me get my code working.
I have a function that takes an id, and makes a call to firebase firestore to get all the documents in a "feedItems" collection. Each document contains two fields, a timestamp and a post ID. The function returns an array with each post object. This part of the code (getFeedItems below) works as expected.
The problem occurs in the next step. Once I have the array of post ID's, I then loop over the array and make a firestore query for each one, to get the actual post information. I know these queries are asynchronous, so I use Promise.all to wait for each promise to resolve before using the final array of post information.
However, I continue to receive "undefined" as a result of these looped queries. Why?
const useUpdateFeed = (uid) => {
const [feed, setFeed] = useState([]);
useEffect(() => {
// getFeedItems returns an array of postIDs, and works as expected
async function getFeedItems(uid) {
const docRef = firestore
.collection("feeds")
.doc(uid)
.collection("feedItems");
const doc = await docRef.get();
const feedItems = [];
doc.forEach((item) => {
feedItems.push({
...item.data(),
id: item.id,
});
});
return feedItems;
}
// getPosts is meant to take the array of post IDs, and return an array of the post objects
async function getPosts(items) {
console.log(items)
const promises = [];
items.forEach((item) => {
const promise = firestore.collection("posts").doc(item.id).get();
promises.push(promise);
});
const posts = [];
await Promise.all(promises).then((results) => {
results.forEach((result) => {
const post = result.data();
console.log(post); // this continues to log as "undefined". Why?
posts.push(post);
});
});
return posts;
}
(async () => {
if (uid) {
const feedItems = await getFeedItems(uid);
const posts = await getPosts(feedItems);
setFeed(posts);
}
})();
}, []);
return feed; // The final result is an array with a single "undefined" element
};
There are few things I have already verified on my own:
My firestore queries work as expected when done one at a time (so there are not any bugs with the query structures themselves).
This is a custom hook for React. I don't think my use of useState/useEffect is having any issue here, and I have tested the implementation of this hook with mock data.
EDIT: A console.log() of items was requested and has been added to the code snippet. I can confirm that the firestore documents that I am trying to access do exist, and have been successfully retrieved when called in individual queries (not in a loop).
Also, for simplicity the collection on Firestore currently only includes one post (with an ID of "ANkRFz2L7WQzA3ehcpDz", which can be seen in the console log output below.
EDIT TWO: To make the output clearer I have pasted it as an image below.
Turns out, this was human error. Looking at the console log output I realised there is a space in front of the document ID. Removing that on the backend made my code work.

Async/Await variable affectation in javascript for loop

I would like to achieve the following thing in JS but I've got the feeling that I don't have the right approach.
I'm doing a first request giving me a list of objects
For each object I'm doing another request to an API to get matching values
Apply a specific logic to the result
Finally call a function that uses the data provided by the API and modified
My code looks like this :
async function processData(){
const models = await fetch('/api/models').then(response => response.json());
for(let m in models){
for(let i of models[m].items){
if(i.type == 1){
i.values = await fetch('/api/main/'+i.id).then(response => response.json());
}
else{
i.values = await fetch('/api/custom/'+i.id).then(response => response.json());
// + additionnal specific code on values
}
console.log(i.values);//<--- NOT WHAT EXPECTED
}
display(models[m]);
}
}
My problem is that display function is called before i.values is updated.
I think the whole for(let i models[m].items){} loop should be asynchronous and the display function should be called only once all fetch requests for each i item have been resolved.
But I'm struggling to write the code and I'm not sure this is the good way of doing this.

Return value of crud functions

I have simple table scripts in Azure written in javascript and node.js.
Now, if I call any of these from Windows Phone, the object parameter gets updated automatically from the return value. And thus code like this works
await table1.InsertAsync(val1);
MyObj val2 = new MyObj();
val2.data = val1.Id;
await table2.InsertAsync(val2);
However now I try to utilize this same from scheduled job in Azure: essentially chaining 2 insert calls so that latter depends on the id of the former. The id column is identity and gets created automatically.
How can I achieve this? Scheduled job is written in javascript/node.js. I have tried
var res = table1.insert(val1);
And using val1.id after the first insert, but neither works.
And of course just moments after I post the question I come up with an answer.
table1.insert(val1, {
success: function(res) {
var val2 = {
data: res.id
}
table2.insert(val2);
}
});

Categories

Resources