Node.js returning an API response within an async function - node.js

I have written the following code to retrieve song lyrics from the apiseeds lyric api.
const apiseeds = require("apiseeds-lyrics");
const apiseedskey = "MY_API_KEY";
async function getLyrics(artistName, songName)
{
return await apiseeds.getLyric(apiseedskey, artistname, songName,
(response) => {
return response;
});
}
var artist = "Darius Rucker";
var title = "Wagon Wheel";
var lyrics = await getLyrics(artist, title)
console.log(lyrics);
I should also mention that the second block of code there is enclosed within an eventEmitter.on event with an asynchronous callback function.
Whenever the code runs, I get undefined in the console.

async and await can only be used to treat asynchronous functions that returns Promises, not callbacks. You should be able to transform your call to use Promises, or use another library.
The main reason we use await is to wait for the promise to resolve before continuing the code execution:
const result = await codeThatReturnsPromise()
console.log(result)
We could transform your code to this:
// async here means it returns a promise
async function getLyrics(artistName, songName)
{
return new Promise((resolve, reject) => {
apiseeds.getLyric(apiseedskey, artistname, songName, (response) => resolve(response))
})
}
var artist = "Darius Rucker";
var title = "Wagon Wheel";
var lyrics = await getLyrics(artist, title)
console.log(lyrics);

Related

How to call a function that waits for return of API call (Node.js)

While learning Node.js and after some trial and error I have this working code that makes API calls to retrieve user records where each API call is dependent on the result of the previous API call.
const axios = require('axios')
var getDataById = async (config) => {
var response = await axios(config);
var userById = {};
userById['userId'] = response.data["userId"];
return(userById);
};
(async () => {
var a = []; // array for storing user data
var userId = '0001';
var done = false; // false until user '0010' is reached
while (!done) {
url = "https://someurl.com/" + userId;
var axiosconfig = {
method: 'get',
url: url,
headers: {
'Authorization': 'Bearer SECRET_TOKEN'
}
};
var userDataById = await getDataById(axiosconfig);
a.push(userDataById);
userId = userDataById['userId'];
if (userId == '0010') { done = true }
}
})()
How can I call this code from elsewhere in my program in such a way that
I can pass arguments to it...for example 'userId'
I can return 'a' to the calling function
the calling function waits for 'a' to be returned before continuing
TBH, I don't quite get how this works.
;(async () => {})()
Is there a better way of coding this?
You need to create an async function and then await it.
The function definition will look like this
async function AddUser(userId)
You can return any variable and you call it like this:
await addUser('002')
await keyword make sure that the calling function waits for 'a' to be returned before continuing.
For your last question:
(async () => {})()
Is an arrow function.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Using async keyword + arrow function is a trick to allow you to create an async context and being able to use await. The two last () are used to direct call this function.

Node.js Await Async with util class function

I am fairly new to Node.js and I am trying to pick it up with Koa.js framework.
I am struggling to understand why the index.js -> console.log run even if I have the await in the value.
Can anyone point me in the right direction?
index.js
router.get('getValue','/display',async (ctx) => {
var myUtilfunction = require('../util')
var result = await myUtilfunction.getData()
console.log(result)
}
util.js
async function getData(){
var customObject =[]
var standardObject =[]
conn.describeGlobal(function (err,res){
if (err){return console.error(err)}
console.log('No of Objects ' + res.sobjects.length)
res.sobjects.forEach(function(sobject){
if (sobject.custom){
customObject.push(sobject)
}else{
standardObject.push(sobject)
}
})
console.log("Done")
})
return [customObject, standardObject]
}
Try this one
await, works inside async functions
router.get('getValue','/display', async (ctx) => {
var myUtilfunction = require('../util')
var result = await myUtilfunction.getData();
console.log(result)
});
function getData(){
return new Promise((resolve, reject) => {
resolve('result goes here');
});
}
You need to specify the function is async for the await to work.
Something like this:
router.get('getValue','/display', async (ctx) => {
var myUtilfunction = require('../util')
var result = await myUtilfunction.getData()
console.log(result)
}
Hope this helps :)
In your function getData(), I think you've missplaced your return statement. The return statement should be placed inside the callback function used for conn.describeGlobal().
As you actually write your getData(), the conn.describeGlobal() call seems to be an asynchronous treatment, so the return statement placed outside is probably executed before you pushed something in your arrays.
The consequence is that your router get an empty response from your getData() function then the promise made by await keyword is resolved with an empty answer.

Nodejs promise async/await not working properly

Not getting api response of 3500 records inside the promise method. If I call api using setTimeout(), it is working and getting all the data.
Please find the sample code below, (calling apiCall in async method only)
let data = await apiCall();
function apiCall(){
return new Promise((resolve,reject)=>{
let options = {method:'get'}
fetch('http://example.com/getData',options).then(data => {
resolve(data);
});
});
}
let data = await apiCall();
function apiCall(){
let options = {method:'get'};
return fetch('http://example.com/getData', options);
}
try like this and it should work fine.
This line here, let data = await apiCall();, is invalid if you're not calling inside async function becuase await is valid only inside async function.
The proper syntax for using async/await is:
async function myFunc() {
let result = await getSomething()
...
}
Also fetch API supports Promise, so in your code you could do:
// note async keyword
async function apiCall(){
let options = {method:'get'}
try {
let response = await fetch('http://example.com/getData',options) // response is also a promise so
let data = await response.json(); // data contains the result
console.log(data);
} catch (err) {
console.error(err)
}
}
Say if you do return data in your apiCall function then the result is also wrapped in promise by async function. So you'll have to:
apiCall().then(result => console.log(result)). And again async/await usage is above ^

Promise not waiting for firebase query to complete and gets resolved too soon

I have created a promise, which would take an array of firebase keys as input, loop them to query firebase realtime database. My issue is even after I use async await, for firebase to provide results back, promise is getting resolved quickly.
function firebaseQuery(keys){
const result = [];
return new Promise((resolve, reject) => {
keys.forEach((key) => {
const snap = app.child(key).once('value');
const snapJSON = await snap.then(snapshot => snapshot.toJSON());
result.push({ key: key, post: snapJSON });
console.log(result);
});
resolve(result);
});
}
forEach does not pause for await statements, so it won't work like this (https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404). Better to map the keys into an array of promises, and then use Promise.all() to wait until they all resolve. Something like this (just make sure to handle your errors)
async function firebaseQuery(keys){
const result = await Promise.all(keys.map(async key => {
const snap = app.child(key).once('value');
const snapJSON = await snap.then(snapshot => snapshot.toJSON());
const returnValue = { key: key, post: snapJSON };
console.log(returnValue);
return returnValue;
}));
}

Await - Async does not make function synchronous in behaviour

I am trying to run the following function which performs request.get to an array of URL's, and then write to an array, the whole operation needs to be synchronous. But my code is not synchronous, and prints different output each time:
var arrayPart = [];
fileDecode : async function(fileName,filePath){
for (a=0; a< arr.length; a++){
var partID = JSON.parse(arr[a].id)
var uri = listID[remainder]+'/download/'+'?id='+partID
await request.get(uri, this.onRequestDone);
}
onRequestDone: async function(err, resp, body){
await new Promise(function (resolve, reject) {
if(err){
reject(err)
}else{
const buf = Buffer.from(body)
console.log("buf", buf)
arrayPart.push(buf);
fs.writeFileSync('message.txt', arrayPart)
resolve(body)
}
});
}
}
my onRequestDone function does not behave correctly and prints buff differently.
The fact that request.get accepts second callback argument means that it it's callback-based and doesn't support promises. It doesn't return a promise to await. It generally doesn't make sense to provide async function as a callback in places where returned promise is ignored.
request-promise package can be used instead:
const request = require('request-promise');
...
const res = await request.get(uri);
const buf = Buffer.from(res.body);
...

Resources