Method does not await for fetch to complete - javascript

I am using Node Ytdl in order to obtain metadata of videos. I have a 'provider' function which I want to return the metadata object of a video.
const getMetaD = async (mediaID) => {
let obj = {};
await ytdl.getInfo(mediaID, {}, async (err, info) => {
if (err) console.log(err);
let format = await ytdl.chooseFormat(info.formats, { quality: 'highest' });
if (format) {
console.log('Format found!', format);
obj = { url: format.url, thumbnail: info.thumbnail, title: info.title };
}
});
return obj;
}
However, my getMetaD function never returns the object assigned in the if(format) block. It will always return the obj = {}. What am I doing wrong? Why doesn't my code await for the results to be assigned to obj before returning it?

You are using await on a callback. It only works on promises. You can achieve the same thing by doing this though.
const getMetaD = (mediaID) => {
return new Promise((resolve, reject) => {
let obj = {};
ytdl.getInfo(mediaID, {}, async (err, info) => {
if (err) console.log(err);
let format = await ytdl.chooseFormat(info.formats, { quality: 'highest' });
if (format) {
console.log('Format found!', format);
obj = { url: format.url, thumbnail: info.thumbnail, title: info.title };
}
resolve(obj);
});
})
}

ytdl.getInfo will return a Promise if you don't pass in a callback
So, you would rewrite your code as follows (no error checking here, but then you don't do any in your code either)
const getMetaD = async (mediaID) => {
let obj = {};
const info = await ytdl.getInfo(mediaID, {});
const format = await ytdl.chooseFormat(info.formats, { quality: 'highest' });
if (format) {
console.log('Format found!', format);
obj = { url: format.url, thumbnail: info.thumbnail, title: info.title };
}
return obj;
}

Related

How can I get value in [Object]

I'm working on coinmarketcap.com api and I need only name and price and save to Mongo. It is working but at the end undefined value returned. Price value is under the quote. What is wrong ?
const axios = require('axios');
let response = null;
new Promise(async (resolve, reject) => {
try {
response = await axios.get('https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=2', {
headers: {
'X-CMC_PRO_API_KEY': 'myKey',
},
});
} catch(ex) {
response = null;
console.log(ex);
reject(ex);
}
if (response) {
const coin = response.data;
console.dir(coin, { depth: null });
console.log(coin.data.map(a => { a.name, a.quote.price}));
resolve(coin);
}
}
);
You shuldn't be wrapping this in another Promise (see: What is the explicit promise construction antipattern and how do I avoid it?) , just make a method which is async
async function getCoin(){
try {
const response = await axios.get('https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=2', {
headers: {
'X-CMC_PRO_API_KEY': 'YOURKEY',
},
});
const coin = response.data;
console.dir(coin, { depth: null });
return coin;
} catch(ex) {
console.log(ex);
throw ex;
}
}
quote contains prices identified by their keys like this:
"quote": {
"USD": {
"price": 42177.91536878145,
"volume_24h": 18068350418.6717,
"volume_change_24h": 8.1323,
"percent_change_1h": -0.02144759,
"percent_change_24h": -0.48235688,
"percent_change_7d": -0.65364542,
"percent_change_30d": -1.87762517,
"percent_change_60d": -13.80076009,
"percent_change_90d": -30.24448455,
"market_cap": 799599134284.9932,
"market_cap_dominance": 42.7605,
"fully_diluted_market_cap": 885736222744.41,
"last_updated": "2022-02-14T09:35:00.000Z"
}
}
so in order to solve the bug, you need to specify the proper key here (USD for example):
I tested this code and it works please copy it inside the separate js file and check the result(Replace your API key):
const axios = require('axios');
let response = null;
async function getCoin(){
try {
const response = await axios.get('https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=2', {
headers: {
'X-CMC_PRO_API_KEY': 'KEY',
},
});
const coin = response.data;
const result = coin.data.map(a => ({ name: a.name, price: a.quote['USD'].price}))
console.log(result)
return coin;
} catch(ex) {
console.log(ex);
throw ex;
}
}
getCoin()
const axios = require("axios");
async function fetchData() {
try {
const response = await axios.get(
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=2",
{
headers: {
"X-CMC_PRO_API_KEY": "myKey",
},
}
);
return [response, null];
} catch (error) {
return [null, error];
}
}
// in your calling function code base
const [response,error] = await fetchData()
if(response){
// handle response object in calling code base
const coin = response.data
}
if(error){
// handle error explictly in calling code base
}
Getting price in quote.USD or quote['USD'] and also need to return object of name and price using map.
So Try this:
const axios = require('axios');
let response = null;
new Promise(async (resolve, reject) => {
try {
response = await axios.get('https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=2', {
headers: {
'X-CMC_PRO_API_KEY': '5345bcb4-0203-4374-bef6-d67a89a6d216',
},
});
if (response) {
const coin = response.data;
cointData = coin.data.map(a => ({ name: a.name, price: a.quote.USD.price }))
resolve(cointData);
}
} catch (ex) {
response = null;
console.log(ex);
reject(ex);
}
});

API GET request returns undefined in Node JS

I'm new to Node JS and still figuring out how API GET requests are working. I'm trying to call API GET request using Node Js, function is supposed to get data from the servers and url will be "url/books?name=" where "name" will be passed to the function from input field. So far I have this function
async function getBooksInfo(name) {
const url = `https://test/books?name=${name}`;
return new Promise(function (resolve, reject) {
https.get(url, res => {
res.setEncoding("utf8");
let body = "";
res.on("data", data => {
body += data;
});
res.on("end", () => {
body = JSON.parse(body);
resolve(body)
});
res.on("error", (e) => {
reject(e);
});
});
})
}
and another function will create stream of inputs,
async function storeInfo() {
const date = readLine().trim();
const result = await getBooksInfo(date);
const isEmpty = !Object.keys(result).length;
if (isEmpty) {
ws.write('We don't have this book in our database');
} else {
ws.write(`Book Name: ${result.bookName}`);
ws.write(`Year: ${result.year}\n`)
}
}
but for some reason stream of inputs return undefined, I don't seems to understand what could be the issue. Any help and suggestion is greatly appreciated.
Updated: this is what console.log shows
{
page: 1,
per_page: 100,
total_pages: 20,
data: [
{
bookName: 'test',
year: 1975,
author: "test,
}
]
}

Can we use async/await in cloud functions in firebase?

I have to functions called: getMatchDataApi() and saveApiDataToDb(). getMatchDataApi() function returns value from an api and saveApiDataToDb() function is used to store getMatchDataApi() value into firestore database.
function getMatchDataApi() {
var options = {
method: "GET",
hostname: "dev132-cricket-live-scores-v1.p.rapidapi.com",
port: null,
path: "/scorecards.php?seriesid=2141&matchid=43431",
headers: {
"x-rapidapi-host": "dev132-cricket-live-scores-v1.p.rapidapi.com",
"x-rapidapi-key": "63e55e4f7fmsh8711fb1c0bd9ec2p1d8b4bjsne2b8db0a1a82"
},
json: true
};
var req = http.request(options, res => {
var chunks = [];
res.on("data", chunk => {
chunks.push(chunk);
});
res.on("end", () => {
var body = Buffer.concat(chunks);
var json = JSON.parse(body);
playerName = json.fullScorecardAwards.manOfTheMatchName;
console.log("player name", playerName);
});
});
req.end();
}
async function saveApiDataToDb() {
await getMatchDataApi();
var name = playerName;
console.log("Aman Singh", name);
}
Here i am using async function. So that first i want it should execute this getMatchDataApi() first and returns the value and after that it should print value inside this function saveApiDataToDb().
And then i am calling saveApiDataToDb() as follow:
exports.storeMatchData = functions.https.onRequest((request, response) => {
saveApiDataToDb()
});
Yes, you can use async/await in cloud functions. But, you can't access/fetch the data outside the google servers in the Spark Plan (Free Plan).
Hope this helps.
Modify your functions/index.js file like this way:
const functions = require('firebase-functions');
const request = require('request');
exports.storeMatchData = functions.https.onRequest( async (req, res) => {
let body = '';
await getMatchDataApi().then(data => body = data).catch(err => res.status(400).end(err));
if (!body) {
return res.status(404).end('Unable to fetch the app data :/');
}
// let json = JSON.parse(body);
// playerName = json.fullScorecardAwards.manOfTheMatchName;
// console.log("Aman Singh", playerName);
res.send(body);
});
function getMatchDataApi() {
const options = {
url: 'https://dev132-cricket-live-scores-v1.p.rapidapi.com/scorecards.php?seriesid=2141&matchid=43431',
headers: {
"x-rapidapi-host": "dev132-cricket-live-scores-v1.p.rapidapi.com",
"x-rapidapi-key": "63e55e4f7fmsh8711fb1c0bd9ec2p1d8b4bjsne2b8db0a1a82"
},
};
return cURL(options);
}
function cURL(obj, output = 'body') {
return new Promise((resolve, reject) => {
request(obj, (error, response, body) => {
if (error)
reject(error);
else if (response.statusCode != 200)
reject(`cURL Error: ${response.statusCode} ${response.statusMessage}`);
else if (response.headers['content-type'].match(/json/i) && output == 'body')
resolve(JSON.parse(body));
else if (output == 'body')
resolve(body);
else
resolve(response);
});
});
}
I try to solve my issue using promise in cloud functions. so it could help someone.
This is my cloud function
exports.storeMatchData = functions.https.onRequest((request, response) => {
a().then(
result => {
saveApiDataToDb(result);
},
error => {}
);
});
This is the function from which i am calling api and resolving its data first what i want
var options = {
method: "GET",
hostname: "dev132-cricket-live-scores-v1.p.rapidapi.com",
port: null,
path: "/scorecards.php?seriesid=2141&matchid=43431",
headers: {
"x-rapidapi-host": "dev132-cricket-live-scores-v1.p.rapidapi.com",
"x-rapidapi-key": "63e55e4f7fmsh8711fb1c0bd9ec2p1d8b4bjsne2b8db0a1a82"
},
json: true
};
var options1 = {
method: "GET",
hostname: "dev132-cricket-live-scores-v1.p.rapidapi.com",
port: null,
path: "/matches.php?completedlimit=5&inprogresslimit=5&upcomingLimit=5",
headers: {
"x-rapidapi-host": "dev132-cricket-live-scores-v1.p.rapidapi.com",
"x-rapidapi-key": "63e55e4f7fmsh8711fb1c0bd9ec2p1d8b4bjsne2b8db0a1a82"
}
};
var a = function getMatchDataApi() {
// Return new promise
return new Promise((resolve, reject) => {
// Do async job
let firstTask = new Promise((resolve, reject) => {
var req = http.request(options, res => {
var chunks = [];
var arr = [];
res.on("data", chunk => {
chunks.push(chunk);
});
res.on("end", () => {
var body = Buffer.concat(chunks);
var json = JSON.parse(body);
const playerName = json.fullScorecardAwards.manOfTheMatchName;
resolve(playerName);
});
});
req.end();
});
let secondTask = new Promise((resolve, reject) => {
var req = http.request(options1, res => {
var chunks = [];
var arr = [];
res.on("data", chunk => {
chunks.push(chunk);
});
res.on("end", () => {
var body = Buffer.concat(chunks);
var json = JSON.parse(body);
const playerName = json;
resolve(playerName);
});
});
req.end();
});
Promise.all([firstTask, secondTask]).then(
result => {
resolve(result);
},
error => {
reject(error);
}
);
});
};
This is the function in which I am going to use getMatchDataApi() values after resolving in this function.
function saveApiDataToDb(data) {
console.log("Name of player", data[0]);
}

how can use async inside .map

hi coders i have problem with this code:
const ForVideo = async data =>
data.map(story => {
return {
videoUrl: story.video.versions[0].url,
instagramId: story.pk,
videoFilename: MediaDownloader({
url: story.video.versions[0].url,
dest: "/Users/Hernan/Haip/media/" + story.account.pk + "/story/"
}),
expiresAt: story.expiringAt,
tappableObjects: HashMention(story),
influencerId: story.account.pk,
takenAt: story.takenAt,
isVideo: true,
videoDuration: story.video.duration,
displayUrl: story.imageVersions2.candidates[0].url,
imageFilename: MediaDownloader({
url: story.imageVersions2.candidates[0].url,
dest: "/Users/Hernan/Haip/media/" + story.account.pk + "/story/"
}),
callToAction: null
};
});
i call ForVideo (data) function that return a new JSON but the problem is that this dont return the item videoFilename andimageFilename (url from MediaDownloader() function)
how can i apply async / await or promise to get the full JSON and wait to MediaDownloader() function to finish ?
MediaDownloader() :
MediaDownloader: async options => {
let dir = options.dest;
try {
fs.ensureDirSync(dir);
const { filename, image } = await download.image(options);
return filename;
} catch (e) {
console.error(e);
}
}
try this.
const ForVideo = data =>
data.map(async story => {
return {
videoFilename: await MediaDownloader({
url: story.video.versions[0].url,
dest: "/Users/Hernan/Haip/media/" + story.account.pk + "/story/"
})
};
});
MediaDownloader: options => {
return new Promise((resolve, reject) => {
let dir = options.dest;
try {
fs.ensureDirSync(dir);
const { filename, image } = download.image(options);
resolve(filename);
} catch (e) {
reject(e);
}
});
}

how can i print result array in node js outside mongoOp find query?

I am new in Node.js and I want to pass data array to controller. But I am unable to insert for loop data in array and I also want to get result data out side function.
router.get("/list-group", function(req, res) {
sess = req.session;
var response = {};
if (sess.loginData) {
var TableData = [];
var i = {};
var result = [];
mongoOp.users_group.find({
group_id: req.query.group_id
}, function(e, d) {
var len = d[0].assign_user_id.length;
var assignuserid = d[0].assign_user_id;
for (var i = 0; i < assignuserid.length; i++) {
var assignid = assignuserid[i];
mongoOp.users.find({
_id: assignid
}, function(err, data) {
// This is result array
result[i] = data;
})
}
// And I want to print result array here
console.log(result);
});
} else {
response = {
"error": true,
"message": "Invalid Login"
};
res.json(response);
}
})
I would make use of async and await
router.get('route', (req, res) => {
// ...
users.find(query, (err, d) => {
try {
// ...
var results = []
for (var data of array) {
const result = await fetchUser(data)
results.push(result)
}
console.log(results)
} catch (err) {
console.log('some error occured', err)
}
})
})
async function fetchUser(id) {
return new Promise((resolve, reject) => {
users.find({ _id: id }, (err, data) => {
return err ? reject(err) : resolve(data)
})
})
}
If you're not that familiar with async and await I would recommend this video
u need read about async and callbacks in javascript. An alternative is read about async and await.

Categories