Fetch data containing a variable - javascript

So my goal is to get the uuid from a Minecraft username via the Mojang api and then run it through the Hypixel Skyblock api. My problem is that I cant use the variable ${jsonsbid.id} inside JSON.stringify. I'm quite new to coding and I cant seem to get it working.
I'm using the Discord.js api to send out the JSON result as message.
import { key } from './config.json';
client.on('message', message => {
const prefix = '!skyblock ';
const skyblock = message.content.slice(prefix.length);
const fetch = require('node-fetch');
if (!message.content.startsWith(prefix) || message.author.bot) return; {
try {
fetch(`https://api.mojang.com/users/profiles/minecraft/${skyblock}`)
.then(response => response.json())
.then(jsonsbid => fetch(`https://api.hypixel.net/Skyblock/profiles?uuid=${jsonsbid.id}&key=${key}`))
.then(responsesb => responsesb.json())
.then(jsonsb => message.channel.send(`Coins: ${JSON.stringify(jsonsb.profiles[0].members.${jsonsbid.id}.coins_purse)}`)) //this is the line i need to get working
} catch (err) {
message.channel.send('A error occured')
}
};
Well I hope you can help me so I can learn more about coding and js.

You could create a cache called jsonsbidCache in your bot that stores the jsonsbid JSON result by the key skyblock. You can then later access it in the final .then call.
If you only need to reference jsonsbid.id, then you could modify this to only cache said id value.
import { key } from './config.json';
const mojangApiUrl = 'https://api.mojang.com';
const skyblockApiUrl = 'https://api.hypixel.net/Skyblock';
const displayCoins = (member) => {
return `Coins: ${JSON.stringify(member.coins_purse)}`;
};
const jsonsbidCache = new Map(); // Cache
client.on('message', message => {
const prefix = '!skyblock ';
const skyblock = message.content.slice(prefix.length);
const fetch = require('node-fetch');
if (!message.content.startsWith(prefix) || message.author.bot) {
return;
}
try {
fetch(`${mojangApiUrl}/users/profiles/minecraft/${skyblock}`)
.then(response => response.json())
.then(jsonsbid => {
jsonsbidCache.set(skyblock, jsonsbid); // Cache it
return fetch(`${skyblockApiUrl}/profiles?uuid=${jsonsbid.id}&key=${key}`)
})
.then(responsesb => responsesb.json())
.then(jsonsb => {
const memberId = jsonsbidCache.get(skyblock).id;
const member = jsonsb.profiles[0].members[memberId];
message.channel.send(displayCoins(member))
})
} catch (err) {
message.channel.send('A error occured');
}
}

Related

How can I retrieve and loop through data retrieved from a fetch request?

I am using an open-source api to retrieve breweries when people search by city name. I can console. log the promise returned but when I try to loop and console.log the data it tells me undefined.
const searchBtn = document.getElementById('beer-search-button');
const getBeerData = (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${cityName}`;
encodeURI(beerApi);
fetch(beerApi)
.then(res => {
if(res.ok) {
console.log(res.json());
for(let b in res) {
console.log(b.name);
}
} else {
console.log('Error!');
}
});
}
searchBtn.addEventListener('click', function(e) {
e.preventDefault;
let searchQuery = document.getElementById('city-input').value;
getBeerData(searchQuery);
});
You need to loop over the result of res.json(). You do this with another .then().
And calling encodeURI() without using the result has no effect. You should be calling encodeURIComponent() on the city name, and using that in the URI.
const getBeerData = (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${encodeURIComponent(cityName)}`;
fetch(beerApi)
.then(res => {
if (res.ok) {
return res.json()
} else {
throw "Error";
}
}).then(res => res.forEach(b => console.log(b.name)));
}
You've logged the promise but you haven't parsed that JSON. You can't loop over an array if it doesn't exist. And, because it's an array you should be using a for/of loop for (const b of data)....
Here's a shortened version.
// Get the data
fetch(beerApi)
// Parse the data
.then(res => res.json())
// Loop over the data
.then(data => {
for (const b of data) {
console.log(b.name);
}
});
});
res.json() also returns a Promise which you need to await either using then() or using await which is certainly my preferred option.
Please note that there is no need to URL encode the whole string as the API's URL is already encoded correctly, so you just need to URI encode the city name. Another thing you should probably do, is wait for the DOM to be loaded using DOMContentLoaded event before assigning event listeners as otherwise problems could occur because the DOM element might not yet be present.
const getBeerData = async (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${encodeURIComponent(cityName)}`;
const res = await fetch(beerApi);
if (res.ok) {
const breweries = await res.json();
breweries.forEach(brewery => console.log(brewery));
} else {
console.log("Error!");
}
};
window.addEventListener("DOMContentLoaded", event => {
const searchBtn = document.getElementById("beer-search-button");
searchBtn.addEventListener("click", async function (e) {
e.preventDefault;
let searchQuery = document.getElementById("city-input").value;
await getBeerData(searchQuery);
});
})
<input type="text" id="city-input" name="city-input">
<button id="beer-search-button">Search for breweries!</button>

React jsonserver promise result issue

I am creating a react/ redux app with json fake api server I am trying to add a login and trying to get data from json fake api server, data is showing and all ok , but data is always resulting as a promise and the required data is inside the promise. i tried many ways to distructure but throwing errors , could anyone help me on this,
my axios request
const urlss = "http://localhost:5000/users";
export const userslist = async () => {
const r = await axios.get(urlss);
const data = r.data;
return data;
};
const newout2 = userslist();
const newout = newout2;
console.log(newout);
the place where I am using it
export const login = (credentials) => (dispatch) => {
return new Promise((resolve, reject) => {
const matchingUser =
newout2 &&
newout2.find(({ username }) => username === credentials.username);
if (matchingUser) {
if (matchingUser.password === credentials.password) {
dispatch(setUser(matchingUser));
resolve(matchingUser);
} else {
dispatch(setUser(null));
reject("Password wrong");
}
} else {
dispatch(setUser(null));
reject("No user matching");
}
});
};
i am getting this error
You are using then in your userslist method while awaiting in an async method. drop the then and just use proper await inside an async method.
const urlss = "http://localhost:5000/users";
export const userslist = async () => {
const r = await axios.get(urlss);
const data = r.data;
return data;
};

How do I use an API in Discord.js?

I was looking for a cool way I could automate some interesting news articles on my discord server. I wanted to use webhooks at first but then decided to go with APIs. I looked all around and saw that I should go with New York Times API but when I went to code it, it came up with a few errors.
const Discord = require("discord.js");
const client = new Discord.Client();
const token = require("./token.js");
const fetch = require('node-fetch');
const prefix = '!';
const trim = (str, max) => str.length > max ? `${str.slice(0, max - 3)}...` : str;
client.once('ready', () => {
console.log('Ready!');
});
client.on('message', async message => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).trim().split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'news') {
const { file } = await fetch('https://api.nytimes.com/svc/topstories/v2/technology.json?api-key=').then(response => response.json());
message.channel.sendMessage(file);
}
}).then((state) => {
assert(state.action === 'DONE', 'should change state');
})
.catch((error) => {
assert.isNotOk(error, 'Promise error');
});
throw
client.login(token);
This is my code, I know this is probably riddled with mistakes but I am just starting out with node.js
I looked at the example from the discord.js website and took some stuff from there. I don't know what I should do and if you could explain it out a little to help me learn that would be great. I keep getting the Unhandled Rejection Promise Warning and the Cannot send an empty message errors. I am using Visual Studio Code.
You can use the async/await to get the results array from the API response, then send the details in embeds. You can either send the first article, a random article or more than one articles.
The following should work, it sends the first three articles:
const { Client, MessageEmbed } = require('discord.js');
const fetch = require('node-fetch');
const token = require("./token.js");
const client = new Client();
const API_KEY = 'QerEdX953-NOT-REAL-hdvgx7UPs';
const prefix = '!';
client.on('message', async (message) => {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const command = args.shift().toLowerCase();
if (command === 'news') {
try {
const response = await fetch(
`https://api.nytimes.com/svc/topstories/v2/technology.json?api-key=${API_KEY}`,
);
const data = await response.json();
if (data.results.length === 0) {
return message.channel.send('There are no top stories for you today 🙊');
}
const embed = new MessageEmbed();
// you could also get the number of stories from args[0]
const MAX_STORIES = 3;
data.results.slice(0, MAX_STORIES).forEach((result) => {
embed.setTitle(result.title);
embed.setDescription(result.abstract);
embed.setURL(result.url);
embed.setTimestamp(result.published_date);
if (result.multimedia.length && result.multimedia[2]) {
embed.setThumbnail(result.multimedia[2].url);
}
message.channel.send(embed);
});
} catch (error) {
message.channel.send('Oops, there was an error fetching the API');
console.log(error);
}
}
});
The response from the Top Stories API does not have a file key and so is undefined. You want to destructure results to access the articles array.
The error message says that you cannot call sendMessage with an empty message (undefined in this case).
I'm not sure of the message you want to send but you can send the link to the first article with the following code, for example.
const res = await fetch(`https://api.nytimes.com/svc/topstories/v2/technology.json?api-key=${NYTIMES_API_KEY}`)
const { results } = await res.json()
if (results.length) {
message.channel.sendMessage(results[0].url)
} else {
message.channel.sendMessage('No articles found')
}

Can I use crawled from Node.js in javaScript?

I'm new to javaScript and trying to crawl a website with node.js. I could check the data in console log, but want to use the data in another javaScript file. How can I fetch the data?
The problem is I've never used node.js. I do javaScript so I know how to write the code, but I don't know how the back-end or server works.
I've tried to open it in my local host but the node method (e.g., require()) didn't work. I found out it's because node doesn't work in browser.(See? very new to js)
Should I use bundler or something?
The steps I thought were,
somehow send the data as json
somehow fetch the json data and render
Here is the crawling code file.
const axios = require("axios");
const cheerio = require("cheerio");
const log = console.log;
const getHtml = async () => {
try {
return await axios.get(URL);
} catch (error) {
console.error(error);
}
};
getHtml()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $bodyList = $("div.info-timetable ul").children("li");
$bodyList.each(function(i, elem) {
ulList[i] = {
screen: $(this).find('a').attr('data-screenname'),
time: $(this).find('a').attr('data-playstarttime')
};
});
const data = ulList.filter(n => n.time);
return data;
})
.then(res => log(res));
Could you please explain what steps should I take?
Also, it would be great if I can get understood WHY the steps are needed.
Thanks alot!
you can try writing your data to a JSON file and proceed, that's one way, then you can use the data as an object in any js file
const appendFile = (file, contents) =>
new Promise((resolve, reject) => {
fs.appendFile(
file,
contents,
'utf8',
err => (err ? reject(err) : resolve()),
);
});
getHtml()
.then(html => {
let ulList = [];
const $ = cheerio.load(html.data);
const $bodyList = $("div.info-timetable ul").children("li");
$bodyList.each(function(i, elem) {
ulList[i] = {
screen: $(this).find('a').attr('data-screenname'),
time: $(this).find('a').attr('data-playstarttime')
};
});
const data = ulList.filter(n => n.time);
return data;
})
.then(res => {
return appendFile('./data.json',res.toString())
}))
.then(done => {log('updated data json')});

Using Promise.All with Firebase Cloud Fxs to fill array with FCM tokens before sendToDevice called

I was wondering if someone could help enlighten me as to how I can successfully execute this code where it waits until the entire array is filled with FCM tokens before firing sendToDevice().
I've been using these links (listed below) as references to try and resolve this but I still can not figure it out so alas here I am on SO seeking guidance. I just need to pass the tokens array once it is filled completely. I've gotten it where it fired multiple times on each push but never where it asynchronously loads and then fires ><
Firebase Real Time Database Structure for File Upload
Promise.all with Firebase DataSnapshot.forEach
https://aaronczichon.de/2017/03/13/firebase-cloud-functions/
exports.sendVenueAnnouncement = functions.database.ref(`/venueAnnouncements/{venueUid}/announcement`).onCreate(event => {
const venueUid = event.params.venueUid;
const announcement = event.data.val();
const getVenueDisplaynamePromise = admin.database().ref(`verifiedVenues/${venueUid}/displayname`).once('value');
return getVenueDisplaynamePromise.then(snapshot => {
const displayname = snapshot.val();
const payload = {
notification: {
title: `${displayname}`,
body: `${announcement}`
}
};
const getSubscriberTokensPromise = admin.database().ref(`subscribers/${venueUid}`).once('value');
return getSubscriberTokensPromise.then(snapshot => {
const tokens = [];
snapshot.forEach(function(childSnapshot) {
const key = childSnapshot.key;
const token = admin.database().ref(`pushTokens/` + key).once('value');
tokens.push(token);
});
return Promise.all(tokens);
}, function(error) {
console.log(error.toString())
}).then(function(values) {
return admin.messaging().sendToDevice(values, payload).then(response => {
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
if (error.code === 'messaging/invalid-registration-token' || error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove)
});
})
})
})
You almost have an understanding of Promises. It looks like you're also mixing callbacks with Promises. Firebase and Cloud Functions for Firebase are completely Promise based so there is no need.
With that said, you're code should look something like the following:
exports.sendVenueAnnouncement = functions.database
.ref(`/venueAnnouncements/${venueUid}/announcement`)
.onCreate(event => {
const venueUid = event.params.venueUid
const announcement = event.data.val()
let payload
let tokens = []
return admin.database()
.ref(`verifiedVenues/${venueUid}/displayname`)
.once('value')
.then(snapshot => {
const displayname = snapshot.val()
payload = {
notification: {
title: `${displayname}`,
body: `${announcement}`
}
}
return admin.database().ref(`subscribers/${venueUid}`).once('value')
})
.then(snapshot => {
snapshot.forEach((childSnapshot) => {
const key = childSnapshot.key
const token = admin.database().ref(`pushTokens/` + key).once('value')
tokens.push(token)
})
return Promise.all(tokens)
})
.then(values => {
return admin.messaging().sendToDevice(values, payload)
})
.then(response => {
const tokensToRemove = []
response.results.forEach((result, index) => {
const error = result.error
if (error) {
if (error.code === 'messaging/invalid-registration-token' || error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove())
}
}
})
return Promise.all(tokensToRemove)
})
})
Notice I don't assign the Promise to a variable. Just return it and chain a then. A Promise can return another Promise.
I suggest watching this Firecast for a better understanding of Promises.

Categories