module.exports returning undefined - javascript

I`m trying to make a translation function with IBM Watson API in "services/ibmWatson/index.js". I receive the response correctly, but when I return the response to the "IncidentController.js" it receives as undefined.
const LanguageTranslatorV3 = require('ibm-watson/language-translator/v3');
const { IamAuthenticator } = require('ibm-watson/auth');
module.exports = {
async translate(phrase, language) {
const languageTranslator = new LanguageTranslatorV3({
authenticator: new IamAuthenticator({ apikey: '<my_API_key>' }),
url: 'https://gateway.watsonplatform.net/language-translator/api/',
version: '2020-03-28',
});
await languageTranslator.translate(
{
text: phrase,
source: 'pt',
target: language
})
.then(response => {
if(response.status=200){
console.log(response.result.translations);
return(response.result.translations);
}
return (["error"]);
})
.catch(err => {
console.log('error: ', err);
return (["error"]);
});
}
}
In the above code the console.log(response.result.translations) returns correctly:
[ { translation: 'Dog run over.' },
{ translation: 'Castration' },
{ translation: 'Ticks' },
{ translation: 'Tuberculosis' } ]
In the in IncidentController.js:
const Watson = require('../../src/services/ibmWatson');
const db_connection = require('../database/connection');
module.exports = {
async index(request, response) {
const incidents = await db_connection('incidents').join('ongs', 'ongs.id', '=', 'incidents.ong_id')
.select([
'incidents.*',
'ongs.name',
'ongs.uf']
);
const titles = [];
incidents.forEach((incident) => { titles.push(incident.title) });
const translated_titles = await Watson.translate(titles, "en");
console.log(translated_titles);
return response.json(incidents);
}
}
In the above code the console.log(response.result.translations) returns undefined.
What is wrong with it?

You are returning response.result.translations to the response callback from then().
Since that callback cannot be accessed by your IncidentController, it returns undefined.
This is one way to solve this problem:
// services/ibmWatson/index.js
translate(phrase, language) {
return new Promise((resolve, reject) => {
try {
const response = await languageTranslator.translate({ /* options */ });
resolve(response); // Return the translations
} catch(error) {
reject(error); // If there's an error, return the error
}
});
}
// IncidentController.js
async index() {
// ...
const translatedTitles = await Watson.translate(titles, "en");
console.log(translatedTitles); // Should be working now
}
I hope I could help you or at least lead you in the right direction.

Related

Async await in for loop

I have this function and I'm trying to push objects into the "groupData" array and then return the response object but when the function successfully runs, I get "response" as a null object. What is wrong with my code can anyone help? How can I make the function to wait for the map function to finish and then return.
const groupList = async (io, socket, userid) => {
var response = {};
try {
var groupData = [];
ddb.get({
TableName: "Tablename",
Key: { Username: userid },
})
.promise()
.then(async (user) => {
if (Object.keys(user).length === 0) {
} else {
const groups = user.Item.Chatgroups;
groups.map((g) => {
ddb.get({
TableName: "Tablename",
Key: { ChatID: g },
})
.promise()
.then(async (data) => {
groupData.push({
ChatID: g,
Chatname: data.Item.Chatname,
Group: data.Item.Group
});
})
.catch((err) => {
console.log("Chat group not found");
});
})
response["groups"] = groupData;
}
})
.catch((err) => {
response["code"] = 400;
response["message"] = "Something Went Wrong";
});
} catch (error) {
console.log(error);
} finally {
return response;
}
};
Use Promise.all and if you use async then make use of await.
Here is how your code could look. I removed the error handling -- first test this and when it works, start adding back some error handling (with try/catch):
const groupList = async (io, socket, Username) => {
const user = await ddb.get({
TableName: "Tablename",
Key: { Username },
}).promise();
if (!Object.keys(user).length) return {};
return {
groups: await Promise.all(user.Item.Chatgroups.map(async ChatID => {
const { Item: { Chatname, Group } } = await ddb.get({
TableName: "Tablename",
Key: { ChatID },
}).promise();
return { ChatID, Chatname, Group };
}))
};
};
I searched too long for this 😭
for await (item of items) {}

parsing data from an api call into a text file using axios

I am parsing data from an API call into a text file. However, I wanted to use async-await and break the call below call into 3 separate functions.
#!/usr/bin/env node
const yargs = require("yargs");
const axios = require("axios");
const fs = require("fs");
const options = yargs
.usage("Usage: -n <name>")
.option("n", {
alias: "name",
describe: "Your name",
type: "string",
demandOption: true,
})
.option("s", { alias: "search", describe: "Search Term", type: "string" })
.argv;
const greetings = `Hello ${options.name}!`;
console.log(greetings);
console.log("Here's a random joke for you: ");
const url = options.search
? `https://icanhazdadjoke.com/search?term${escape(options.search)}`
: " https://icanhazdadjoke.com/";
axios.get(url, { headers: { Accept: "application/json" } }).then((res) => {
if (options.search) {
res.data.results.forEach((j) => {
fs.appendFile("jokes.txt", "\n" + j.jokes, (err) => {});
});
if (res.data.results.length === 0) {
console.log("no joke found 😭");
}
} else {
fs.appendFile("jokes.txt", res.data.joke, (err) => {
if (err) throw err;
console.log("File Updated");
});
}
});
So the above code works absolutely fine and generates the file perfectly, however when I tried to break it into the following below functions, I just get undefined in the text file, I am not sure why this is happening.
const getJoke = async (url) => {
try {
const joke = await axios.get(url, {
headers: { Accept: "application/json" },
});
return joke;
} catch (error) {
console.error(error);
}
};
const parseJokes = (res) => {
if (options.search) {
res.data.results.forEach((j) => {
return `\n ${j.joke}`;
});
if (res.data.results.length === 0) {
console.log("no joke found 😭");
}
} else {
return res.data.joke;
}
};
const addJokeToFile = async () => {
const result = await getJoke(url)
.then((res) => {
parseJokes(res);
})
.catch((err) => {
console.error(`ERROR: ${err}`);
});
fs.appendFile("jokes.txt", result, (err) => {
console.error(err);
});
};
In the second (functional approach) addJokeToFile method, you are waiting for the promise to be resolved using both ways, await and .then, following modification to the code, might help you get through:
const addJokeToFile = async () => {
getJoke(url)
.then((res) => {
// Aside, we should also return some value from parseJokes function for "no joke found 😭" case, or return null and put a check here and only append to file when jokeString is not null.
const jokeString = parseJokes(res);
fs.appendFile("jokes.txt", jokeString, (err) => {
console.error(err);
});
})
.catch((err) => {
console.error(`ERROR: ${err}`);
});
};
Try using appendFile from 'fs/promises' so that you can stick with the async/await style. Since getJoke returns a promise I would expect result to be a Promise<string | undefined> depending on if any errors show up earlier in the chain.
const { appendFile } = require('fs/promises');
const addJokeToFile = async () => {
try {
const result = await getJoke(url);
const parsed = parseJokes(result);
await appendFile('jokes.txt', parsed);
} catch (err) {
console.error(err);
}
};

How to get the result of async / await function?

I would like to return an object from the the async / await function A to pass it to another function.
Currently what I get as a result is Promise{ <pending> }' or undefined.
function A:
const parseRss = data => data.forEach(rssLink => {
const getFeed = async () => {
try {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: []
}
}
feed.items.forEach(item => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`)
});
return emailContent;
} catch (e) {
console.error(e);
}
};
return (async () => {
return await getFeed();
})();
});
Function B:
try {
const data = await getDataWithRss();
const emailData = await parseRss([{rss:'http://reddit.com/.rss'}]); // emailData is undefined
return formatEmail(emailData);
} catch (error) {
console.log(error);
}
How do I return emailContent from function A to use it in function B?
Thanks!
Since you made getFeed as async, no need another async. You are looping through, so return an array of promises. Once the you call use Promise.all to resolve. Since there could be multiple urls to fetch.
const parseRss = (data) =>
data.map((rssLink) => {
const getFeed = async () => {
try {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: [],
},
};
feed.items.forEach((item) => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`);
});
return emailContent;
} catch (e) {
console.error(e);
}
};
return getFeed();
});
try {
const data = await getDataWithRss();
const emailData = await Promise.all(parseRss([{rss:'http://reddit.com/.rss'}])); // emailData is undefined
return formatEmail(emailData);
} catch (error) {
console.log(error);
}
await will not work inside a forEach loop. Use a for...in loop instead.
actually, getFeed() is not necessary inside inner scope, you can use async in map callback:
const parseRss = data => data.map(async rssLink => {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: []
}
};
feed.items.forEach(item => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`)
});
return emailContent;
});

how to return value from a promise function

I have a function which checks whether a device is online or not. Below is the code.
const ping = require('ping');
export function findDevices(device) {
try {
const hosts = [device];
let result = null;
hosts.forEach((host) => {
ping.promise.probe(host)
.then((res) => {
console.log(res.alive)
result = res.alive;
return {
Status: result
}
});
});
} catch (err) {
logger.error(err, '[ config - findDevices() ]');
console.error(err);
return {
Status: "Failed"
}
}
}
I am calling this function in a redux action like this:
export function start(device) {
return dispatch => {
const status = Connectionstatus.findDevices(device);
return dispatch({
type: actionTypes.CONNECTIONSTATUS,
payload: {
ConnectionStatus: status
}
})
};
}
I am expective the status variable to be either true or false. But i am getting as undefined even though i am returning the value inside then of the promise function. i have tried awaiting this call and still its not working. Any help would be much appreciated. Thanks.
If that's the case you can do like this
const getStatus = async () => {
try {
const hosts = [device];
const promises = [];
hosts.forEach((host) => {
promises.push(ping.promise.probe(host));
});
const result = await Promise.all(promises);
const status = result.map((r) => { return r.alive; });
return status;
} catch (err) {
logger.error(err, '[ config - findDevices() ]');
return { status: 'Failed' };
}
};
Not 100% sure what all the vars are, but have you considered using async/await to simplify things a bit like this?
const getStatus122 = async device => {
return await Promise.all([device].map(ping.promise.probe))
.then(({ alive }) => alive)
.then(Status => ({ Status }))
.catch(error => {
logger.error(error, '[ config - findDevices() ]');
return { Status: 'Failed' };
})
}
More on that here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
With Promises you should inspect the promised result either in when or catch callback functions. With async/await the code may look a bit simpler. Here is the version with explicit promises.
const ping = require('ping');
const Connectionstatus = {
findDevices: (device) => {
return ping.promise.probe(device).then((res) => {
const result = res.alive;
console.log(result);
return {
Status: result,
};
}).catch((err) => {
logger.error(err, '[ config - findDevices() ]');
console.error(err);
return {
Status: "failed"
}
});
}
}
export function start(device) {
return dispatch => {
Connectionstatus.
findDevices(device).
then((status) => {
dispatch({
type: actionTypes.CONNECTIONSTATUS,
payload: {
ConnectionStatus: status
}
})
});
};
}
You may see that error handling moved to the catch callback function while the dispatch is done in the then callback function. And this is the answer to your question.

Node-Fetch Mapping Error - Cannot read property 'map' of undefined"

Getting an error with the "map" part when I try and run it Cannot read property 'map' of undefined"
The customers const is declared above so not sure. Where is the undefined is coming from? Does the map need declaring?
const AWS = require('aws-sdk'),
ses = new AWS.SES(),
fetch = require('node-fetch');
exports.handler = async (event) => {
console.log(event.customer_id);
const customers = await getCustomers();
customers.map(async customer => await sendEmailToCustomer(customer));
const customersEmailsPromises = customers.map(async customer => await sendEmailToCustomer(customer));
}
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
return json;
}
catch(e) {
throw e;
}
}
const sendEmailToCustomer = (customer) => new Promise((resolve, reject) => {
ses.sendEmail({
Destination:
{ ToAddresses: [customer.email] },
Message:
{
Body: { Text: { Data: `Your contact option is ${customer.customer_id}` } },
Subject: { Data: "Your Contact Preference" }
},
Source: "sales#example.com"
}, (error, result => {
if (error) return reject(error);
resolve(result);
console.log(result);
})
);
})
getCustomers doesn't return anything which means that customers is set to undefined.
Try this:
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
return json;
}
catch(e) {
throw e;
}
}
You also have to return something from the function that you pass as a parameter to .map
customers.map(async customer => {
return await sendEmailToCustomer(customer);
});
or just:
customers.map(async customer => await sendEmailToCustomer(customer));
And since .map returns a new array (does not mutate the original array), you'll have to store the return value:
const customersEmailsPromises = customers.map(async customer => await sendEmailToCustomer(customer));

Categories

Resources