Using only one API if another one does not have data - javascript

const getUser = async (user) => {
const body = await snekfetch.get('https://www.website.com/api/public/users?name=' + user);
const userInfo = JSON.parse(body.text);
const r = await snekfetch.get('https://www.website.com/api/public/users/' + userInfo.uniqueId + '/profile');
const extraUserInfo = JSON.parse(r.text);
const _message = await client.users.get('437502925019807744').send({ files: ['https://www.website.nl/avatar-imaging/avatarimage?figure=h' + userInfo.figureString + '.png'] });
const avatarImage = _message.attachments.first().url;
return { userInfo, extraUserInfo, avatarImage };
};
getUser(args[0]).then((result) => {
message.channel.send(`${result.userInfo.name}`);
}).catch(function(result) {
console.log(result.userInfo.name);
});
Here I am trying to use 3 API's, however it always goes to the catch, even if one exists and other don't, I tried to only use result.userInfo.name to only use the first API, also in the catch I use the first one, then I tried a name that only has the first API but not the second one however I still get: TypeError: Cannot read property 'name' of undefined because it looks at the second API as well, what else can I do to handle with this situation? So basically how can I only catch errors for the first API
edit: I also tried:
if (extraUserInfo.user.name) {return { userInfo, extraUserInfo, avatarImage };}
else {return { userInfo, avatarImage };}

Fixed it with a try catch
try {
const r = await snekfetch.get('https://www.website.com/api/public/users/' + userInfo.uniqueId + '/profile');
const extraUserInfo = JSON.parse(r.text);
return {
userInfo,
extraUserInfo,
avatarImage
};
} catch (error) {
const extraUserInfo = {
'error': 'not-found'
};
return {
userInfo,
extraUserInfo,
avatarImage
};
}
};
getUser(args[0]).then((result) => {
console.log(result.extraUserInfo.error === 'not-found' ? result.userInfo.name : result.extraUserInfo.user.name);
}).catch((error) => {
console.log(error);
});

Related

Trying to send params to axios in get - react

I'm new here on the site, and new to React.
I built a function that works great in nodejs. There are rare cases where I want to run this function according to the parameters I send it to, so I try to send it the parameters but I think I can not, I try to print it - and I do not get a print of the parameters I want to send.
i run the function throw click at buttom in react:
<Button onClick={() => {
const result = [1,2,3,4,5,"test"];
props.makeMatchVer2(result);
}}>
make match ver2
</Button>
the action I'm run in axios:
export const makeMatchVer2 = (data) => (dispatch) => {
dispatch({ type: LOADING_DATA });
axios
.get('/kmeans', {
params: {
filterArray: data
}
})
.then((res) => {
dispatch({
type: MAKE_MATCH,
payload: res.data
});
})
.catch((err) => {
dispatch({
type: MAKE_MATCH,
payload: []
});
});
};
the function I'm build in nodeJS:
exports.addUserKmeansMatch = (req, res) => {
console.log("addUserKmeansMatch function start:");
console.log(req.data);
if(req.params)
{
console.log(req.params);
}
let userIndex = 0;
let engineers = [];
let engineersHandles = [];
let engineerDetailsNumeric = {};
db.collection("preferences").get().then(querySnapshot => {
querySnapshot.forEach(doc => {
const engineerDetails = doc.data();
if (engineerDetails.handle === req.user.handle) {
engineersHandles.unshift(engineerDetails.handle);
delete engineerDetails.handle;
engineerDetailsNumeric = convertObjectWithStrToNumber(engineerDetails);
engineers.unshift(engineerDetailsNumeric);
}
else {
engineersHandles.push(engineerDetails.handle);
delete engineerDetails.handle;
engineerDetailsNumeric = convertObjectWithStrToNumber(engineerDetails);
engineers.push(engineerDetailsNumeric);
}
});
kmeans.clusterize(engineers, { k: 4, maxIterations: 5, debug: true }, (err, result) => {
if (err) {
console.error(err);
return res.status(500).json({ error: err.code });
} else {
const cluster = result.clusters;
let foundedMatches = GetUserSerialGroup(userIndex, [...cluster], [...engineers]);
let foundedMatchesHandle = GetUserSerialGroupHandle(userIndex, [...cluster], [...engineersHandles]);
let totalTest = {
foundedMatches: foundedMatches,
foundedMatchesHandle: foundedMatchesHandle,
cluster: cluster,
engineersHandles: engineersHandles,
engineers: engineers
};
let userMatchHandle = reduceUserMatchHandle(foundedMatchesHandle);
userMatchHandle.handle = req.user.handle;
db.doc(`/match/${req.user.handle}`)
.set(userMatchHandle)
.then(() => {
return res.json({ message: "Details added successfully" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
}
})
})
};
Through the button, I send parameters to the function, but I do not see their print, probably something does not work, but I do not know why, I'm new to it
makeMatchVer2 is a thunk. You should call it with dispatch: dispatch(props.makeMatchVer2(result))
The code is correct, I accidentally sent the wrong object, I have 2 objects with almost identical names, one array and the other an object. And I accidentally sent the object instead of the array, it's working right now, thank you.

Get the variable data/result from the promise in React JS after running it through map

I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
const CreateCustomer = (storeData) => {
let activeOrganization = null;
storeData.Org
.getOrganization()
.then(function createCustomer(organization) {
activeOrganization = organization[0];
const dataArray= storeData.attributes;
activeOrganization
.createAttributes(
attributeType[0],
getSomeData(dimensions)
)
.then(function Properties(createdAttribute) {
updateCustomerProperty(createdAttribute, attributeType[0]);
});
activeOrganization
.createAttributes(
attributeType[1],
getSomeData(dimensions)
)
.then(function Properties(createdAttribute) {
updateCustomerProperty(createdAttribute, attributeType[1]);
});
}).then(() => {
activeOrganization
.getCustomers()
.then((cusomters) => {
const activeCustomers = [];
cusomters.map((customer) => {
activeCustomers.push(customer);
});
return activeCustomers;
})
.then((activeCustomers) => {
console.log(activeCustomers);
});
});
};
//Now I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
I want the result of activeCustomers array inside the last then but I keep getting an error saying arrow function expects a return. Not sure how I can get activeCustomers?
In your example i think you received a warning. But still how to access to activeCustomers it depends on how you want to use it there are you storing it.
If you want to store it globally then you can store it like that
let activeCustomers;
....
.then((cusomters) => {
activeCustomers = [];
cusomters.map((customer) => {
activeCustomers.push(customer);
});
return activeCustomers;
})
But i think it's better to rewrite to async/await.
const CreateCustomer = async (storeData) => {
let activeOrganization = null;
const [activeOrganization] = await storeData.Org
.getOrganization();
const activeOrgPrs = attributeType.map(x => activeOrganization
.createAttributes(
x,
getSomeData(dimensions)
)));
const attrs = await Promise.all(activeOrgPrs);
attrs.forEach((attr, i) => {
updateCustomerProperty(attr, attributeType[i]);
})
const cusomters = await activeOrganization
.getCustomers();
return cusomters;
};
And you can use it like const customers = await CreateCustomer(someData);
or like CreateCustomer(someData).then((cusomters) => { activeCustomers = cusomters; return null;(if it keeps to return errors)});

Using async and await returns parsing error

I have this function that uses validate from yup and it has async function in it.
If I want to use the whole function how can I wait for it to finish
here is code
const handleSubmit = () => {
companyRef.handleProfileFormSubmit();
setModal(true);
setIsSubmitting(true);
console.log(companyRef.handleFocusOnError());
if (!companyRef.handleFocusOnError() && !isButtonValid) {
console.log('first if in handlesubmut', companyRef.handleFocusOnError());
handleBankDetailsClick();
}
if (isButtonValid && !companyRef.handleFocusOnError()) {
bankRef.handleBankFormSubmit();
history.push(DASHBOARD);
} else if (isButtonValid && companyRef.handleFocusOnError()) {
setIsBankDetailsOpen(true);
}
};
I want to wait for the first sentence to finish which is
companyRef.handleProfileFormSubmit();
the async function is here
handleProfileFormSubmit = () => {
const { profile } = this.state;
const { errorValues } = this.state;
let errorExists = false;
let urls = url.format(profile.website.value);
if (!startsWith(urls, 'http://') && !isEmpty(urls)) {
urls = 'http://' + urls;
}
console.log(urls);
this.schema
.validate(
{
name: profile.name.value,
industry: profile.industry.value,
address: profile.address.value,
crn: profile.crn.value,
website: urls,
employeesNbr: profile.employeesNbr.value,
phoneNumber: profile.phoneNumber.value,
userRole: profile.userRole.value,
personCheck: profile.personCheck.value,
},
{ abortEarly: false },
)
.catch(err => {
errorExists = true;
const errors = {};
for (const i of err.inner) {
errors[i.path] = i.message;
}
const sortedErrors = Object.keys(errors);
sortedErrors.forEach(key => {
profile[key].hasError = true;
profile[key].errorMessage = errors[key];
errorValues.inputErrors.value.push(key);
this.setState({ errorValues });
});
})
.then(() => {
console.log('while submitting', errorValues);
this.handleModalError();
if (errorExists) {
this.props.handleCompanyError();
}
});
};
How can I do this?
You're mixing concerns by putting your validation and submit handler into one, but it's still possible (and fine, extract stuff into functions to make it less complicated).
Below example shows where to handle validation errors and submission errors (if submission is async, which it usually is):
handleProfileFormSubmit = async () => {
try {
await this.schema.validate({...});
// now you know your form is valid - move on to submission
try {
await processSubmission(...);
// submission successful!
} catch(err) {
// error occurred while submitting
}
} catch(err) {
// error occurred while validating
}
};

Sending list of images as response using Javascript

I am making an API that gets a list of image names, then it has to download them one by one from S3 bucket and then send them all as a response.
The issue is that my images are being uploaded but it seems that when I put them in a list as base64 and then try to send the list then the list just comes up empty.
const getImagesById = async (req, res) => {
const { id } = req.params;
const imagesSet = new Map();
try {
const documentFromDB = await document.findOne({ id });
documentFromDB.devices.forEach((device) => {
const images = new Set();
device.images.forEach(item => images.add(downloadFromS3(item)))
imagesSet.set(device.name, JSON.stringify(mapToObj(images))) // tried adding just images also but neither works
});
res.status(200).json(JSON.stringify(mapToObj(imagesSet)));
} catch (e) {
console.log(`An error occurred : ${e.message}`);
res.status(500)
.send(e.message);
}
};
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}
And this is how I get images from S3:
const downloadFromS3 = async (imageName) => {
try {
const image = await S3Utils.downloadFile(BUCKET_NAME, imageName);
if (image.stack) {
return null;
}
const imageBase64 = image.Body.toString('base64');
return imageBase64;
} catch (e) {
console.log(`An error occurred while downloading : ${e.message}`);
throw e;
}
};
This is the response I am getting at the moment:
"{\"{ name: 'Martin'}\":\"{\\\"[object Promise]\\\":{}}\"}"
What I am trying to do is get a lits of device names, map them in a Map as key with value as the base64 list of images and then send it all in a response to the UI to show the images with the names.
What am I doing wrong here?
You just need to add await before call the downloadFromS3 function, consequently changing all the above functions.
const getImagesById = async (req, res) => {
const { id } = req.params;
const imagesSet = new Map();
try {
const documentFromDB = await document.findOne({ id });
await Promise.all(documentFromDB.devices.map(async (device) => {
const images = new Set();
await Promise.all(device.images.map(async item => images.add(await downloadFromS3(item))))
imagesSet.set(device.name, JSON.stringify(mapToObj(images))) // tried adding just images also but neither works
}));
res.status(200).json(JSON.stringify(mapToObj(imagesSet)));
} catch (e) {
console.log(`An error occurred : ${e.message}`);
res.status(500)
.send(e.message);
}
};
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach(function(value, key){
obj[key] = value
});
return obj;
}

Web scraping and promises

I am using cheerio and node to do web scraping, but I have a problem with promises. I can scrape an article list from a page but in that list, we have more links for single pages. I need to scrape single pages as well for each item on the list.
I will show you my code for the better solution.
import rp from 'request-promise'
import cheerio from 'cheerio'
import conn from './connection'
const flexJob = `https://www.flexjobs.com`
const flexJobCategory = ['account-management', 'bilingual']
class WebScraping {
//list of article e.g for page 2
results = [] // [[title], [link for page],...]
contentPage = [] //content for each page
scrapeWeb(link) {
let fullLink = `${link}/jobs/${flexJobCategory[1]}?page=2`
const options = {
uri: fullLink,
transform(body) {
return cheerio.load(body)
}
}
rp(options)
.then(($) => {
console.log(fullLink)
$('.featured-job').each((index, value) => {
//html nodes
let shortDescription = value.children[1].children[1].children[3].children[1].children[1].children[0].data
let link = value.children[1].children[1].children[1].children[1].children[1].children[0].attribs.href
let pageLink = flexJob + '' + link
let title = value.children[1].children[1].children[1].children[1].children[1].children[0].children[0].data
let place = value.children[1].children[1].children[1].children[1].children[3].children[1].data
let jobType = value.children[1].children[1].children[1].children[1].children[3].children[0].children[0].data
this.results.push([title, '', pageLink.replace(/\s/g, ''), '', shortDescription.replace(/\n/g, ''), place, jobType, 'PageContent::: '])
})
})
.then(() => {
this.results.forEach(element => {
console.log('link: ', element[2])
this.scrapePage(element[2])
});
})
.then(() => {
console.log('print content page', this.contentPage)
})
.then(() => {
//this.insertIntoDB()
console.log('insert into db')
})
.catch((err) => {
console.log(err)
})
}
/**
* It's going to scrape all pages from list of jobs
* #param {Any} pageLink
* #param {Number} count
*/
scrapePage(pageLink) {
let $this = this
//console.log('We are in ScrapePage' + pageLink + ': number' + count)
//this.results[count].push('Hello' + count)
let content = ''
const options = {
uri: pageLink,
transform(body) {
return cheerio.load(body)
}
}
rp(options)
.then(($) => {
//this.contentPage.push('Hello' + ' : ');
console.log('Heloo')
})
.catch((err) => {
console.log(err)
})
}
/**
* This method is going to insert data into Database
*/
insertIntoDB() {
conn.connect((err) => {
var sql = "INSERT INTO contact (title, department, link, salary, short_description, location, job_type, page_detail) VALUES ?"
var values = this.results
conn.query(sql, [values], function (err) {
if (err) throw err
conn.end()
})
})
}
}
let webScraping = new WebScraping()
let scrapeList = webScraping.scrapeWeb(flexJob)
So, at 'scrapeWeb' method, at second '.then', I am calling 'scrapePage' method, however, the third promise executed before promise inside 'scrapePage' method.
You need a little more control flow at that stage. You do not want that .then()'s promise to resolve until all the calls are resolved.
You could use a Promise library like bluebird to do a Promise.each or a Promise.map for all the results you want to run.
Or use async/await to set up like .then(async () => {}) and do not use .forEach.
for(let element of this.results){
console.log('link: ', element[2])
await this.scrapePage(element[2])
}
You have a race condition problem.
The first tweak you'll need is having scrapePage returning a Promise.
scrapePage(pageLink) {
let $this = this
let content = ''
const options = {
uri: pageLink,
transform(body) {
return cheerio.load(body)
}
}
return rp(options);
}
In the second than, you need to invoke all child pages scraping eg :
.then(() => {
return Promise.all(this.results.map(childPage => this.scrapePage(childPage)));
})
This will wrap all scrapes of child pages into promises and only if all of them are resolved the code will flow.

Categories

Resources