running a nodeJS function within a csv file - javascript

I have a nodeJS app in which I designed it to run three API calls based on the name of the business and return results. What i want to do is run this app in a CSV file that I have. Below is my code. Any ideas on how to do this? Below is a sample of my code. Im trying to run the name column, pass it inside my functions and return the results inside the CSV file.
function fetchYelp() {
let token = '<Token>';
axios.get('https://api.yelp.com/v3/businesses/search?term=Grace Christian Fellowship&location=Mounds, il 62964',{
headers: {
Authorization: 'Bearer ' + token
}
})
.then(res => {
if(res.data.businesses.length < 1){
fetchWhitePages();
}else{
console.log(res.data.businesses);
console.log('running YelpAPI')
}
})
.catch(err => {
console.log(err)
})
}
fetchYelp();
function fetchWhitePages() {
axios.get('https://proapi.whitepages.com/3.0/business?api_key=<key>&address.city=Mounds&address.country_code=US&address.postal_code=62964&address.state_code=il&name=Grace Christian Fellowship')
.then(res => {
if(!res.data.business.length < 1){
fetchGooglePlace()
}else{
console.log(res.data);
console.log('running whitePagesAPi')
}
})
.catch(err => {
console.log(err)
});
}
function fetchGooglePlace(){
axios.get('https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=Grace Christian Fellowship, mounds il 62964&inputtype=textquery&fields=photos,formatted_address,name,rating,opening_hours,geometry,place_id&key=<APIKEY>')
.then(res => {
if(res.data.candidates.length < 1){
console.log('Manual Search')
}else{
console.log(res.data.candidates[0].place_id);
console.log('Passing Place ID to fetchGoogleTel')
fetchGoogleTel()
}
})
.catch(err => {
console.log(err)
});
}
function fetchGoogleTel ()

Related

Unable to fetch user location details by IP

hello im new to react and trying to build a weather site. i have a search functionality which works, but im also trying to get the local weather for the user.
for this i get city from: https://geoip-db.com/json/
weather api: https://api.openweathermap.org/data/2.5/
then i save that city as a variable in the state so i can use it in the api.
here is the code:
`
state = {
geoipCity: "",
}
componentDidMount(){
const geoApiUrl = "https://geoip-db.com/json/";
fetch(geoApiUrl)
.then(res => res.json())
.then(geoip => {
this.setState({ geoipCity: geoip.city })
})
.catch(err => {
console.log("Fetch error: " + err);
});
console.log("prefetch:" + this.state.geoipCity)
const weatherApiUrl = `${api.base}weather?q=${this.state.geoipCity}&weather&units=metric&APPID=${api.key}`;
fetch(weatherApiUrl)
.then(res => res.json())
.then(result => {
console.log(result)
let locationOutput = document.querySelector("#locationOutput");
if(result.cod === "404"){
locationOutput.innerHTML = `${this.state.geoipCity} is not a valid city name`;
}
/*
locationOutput.innerHTML = `
Your live in ${this.state.geoipCity} and it feels like ${result.main.feels_like}°C`;
*/
})
.catch(err => {
console.log("Fetch error: " + err);
});
}
`
so the first fetch gets the city and saves it in the geoipCity state variable. this i try to use it in the api search.
however right before that i have:
console.log("prefetch:" + this.state.geoipCity)
which shows me that this.state.geoipCity is empty.
any ideas?
EDIT: SOLVED, HERE IS THE CODE IN CASE ANYONE BENEFITS FROM IT IN THE FUTURE
`
componentDidMount(){
const geoApiUrl = "https://geoip-db.com/json/";
fetch(geoApiUrl)
.then(res => res.json())
.then(result => {
console.log(result)
this.setState({ geoipCity: result.city }, () => {
//console.log(this.state);
const weatherApiUrl = `${api.base}weather?q=${this.state.geoipCity}&weather&units=metric&APPID=${api.key}`;
fetch(weatherApiUrl)
.then(res => res.json())
.then(result => {
console.log(result)
let locationOutput = document.querySelector("#locationOutput");
if(result.cod === "404"){
locationOutput.innerHTML = `${this.state.geoipCity} is not a valid city name`;
}
locationOutput.innerHTML = `
Your live in ${this.state.geoipCity} and it feels like ${result.main.feels_like}°C`;
})
.catch(err => {
console.log("Fetch error: " + err);
});
});
//this.setState({ geoipCity: geoip.city })
})
.catch(err => {
console.log("Fetch error: " + err);
});
}
`
this.setState is async.
You need to use the callback of setState in order to console.log the new state.
this.setState({ geoipCity: geoip.city }, (newState) => {
console.log(newState);
});
Every setState will re-render the component but componentDidMount only executes on the first render.

Nock throws a no match for request when using Promise.race

I'm writing a test for some code that will use Promise.race to bring back a result from a graphql service that is on (could be on) multiple servers. I've used Nock to mock the request, which works fine when I'm hitting a single service. When I mock up multiple services, Nock throws an error saying
AssertionError: expected [Function] to not throw an error but 'Error: Error: Nock: No match for request {\n "method": "POST",\n "url": "http://94.82.155.133:35204",\n "headers": {\n "content-type": "application/json",\n "accept": "application/json"\n },\n "body": "{...}"\n}' was thrown
my test looks like this:
it('should make two POST requests to the service for data from graphQL', async () => {
const spy = sinon.spy(releases, '_queryGraphQL');
const releaseID = 403615894;
nock.cleanAll();
const services = serviceDetails(NUMBER_OF_SERVICES); // NUMBER_OF_SERVICES = 3
nock(serviceDiscoveryHost)
.get('/v1/catalog/service/state51')
.reply(HTTP_CODES.OK, services);
for (const service of services) {
const currentNodeHealth = nodeHealth(service.Node);
nock(serviceDiscoveryHost)
.get('/v1/health/node/'+service.Node)
.reply(HTTP_CODES.OK, currentNodeHealth);
const delayTime = Math.floor(Math.random()*1000);
nock('http://'+service.Address+':'+service.ServicePort, serviceHeaders)
.post('/')
.delay(delayTime)
.replyWithError({code: 'ETIMEDOUT', connect: false})
.post('/')
.delay(delayTime)
.reply(HTTP_CODES.OK, getReply(releaseID))
}
const actual = await releases.getRelease(releaseID)
.catch((err) => {
console.log(releases._retries);
(() => { throw err; }).should.not.throw();
});
expect(releases._retries[releaseID]).to.be.equal(1);
expect(spy.callCount).to.be.equal(2);
expect(actual).to.be.an('object')
expect(actual.data.ReleaseFormatById.id).to.be.equal(releaseID);
});
and the offending bit of code looks like
async _queryGraphQL(releaseID, services) {
if (! this._retries[releaseID]) {
this._retries[releaseID] = 0;
}
const postData = this._getReleaseQuery(releaseID);
return Promise.race(services.map( (service) => {
const options = this._getHTTPRequestOptions(service);
return new Promise((resolve, reject) => {
let post = this.http.request(options, (res) => {
let data = '';
if (res.statusCode < 200 || res.statusCode > 299) {
const msg = this.SERVICE_NAME + ' returned a status code outside of acceptable range: ' + res.statusCode;
reject(new QueryError(msg, postData));
} else {
res.setEncoding('utf8');
res.on('data', (chunk) => {
data += chunk;
});
res.on('error', (err) => {
reject(new QueryError(err.message, postData, err));
});
res.on('end', () => {
resolve(JSON.parse(data));
});
}
});
post.on('error', async (err) => {
if (err.code === 'ETIMEDOUT') {
if (this._retries[releaseID] &&
this._retries[releaseID] === 3) {
reject(err);
} else {
this._retries[releaseID] += 1;
resolve(this._queryGraphQL(releaseID, services));
}
} else {
reject(new QueryError(err.message, postData, err));
}
});
post.write(JSON.stringify(postData));
post.end();
});
}));
}
this.http is just require('http');. and the options will be {hostname: service.hostname} \\ example.com etc.
What I'm expecting, is that if the first service to respond, responds with an error relating to: 'ETIMEDOUT', it'll recall the function (upto 2 more times) and try all the services again until the first service to respond is something that isn't a 'ETIMEDOUT'.

Node js pause while loop wait until functions inside get executed completely?

I am coding a post request which downloads all URL HTML,zips them and email it back. This all should happen in the backend. I am storing all the data in an array and extract the first element to start these operations.
I have while loop inside which I am calling some functions. Each function gets executed at a certain time.
I used async, await and promises to make sure they run one after the
other.
Coming to my problem.
My while loop starts getting executed again before all the
functions inside it are executed.
app.post('/?', async (req, res) => {
var urls = req.query.urls
var email = req.query.email;
var new_stack = [urls, email]
stack.push(new_stack)
res.send("Mail sent")
if (isFunctionRunning === false) { //initially it is false
console.log(isFunctionRunning, stack.length)
send_mails();
}
});
const getGoogleIndexHTML = (url) => {
return new Promise((resolve, reject) => {
request(url, (err, res, body) => err ? reject(err) : resolve(body))
})
}
const some_function_to_download = async (url) => {
try {
const a = url.split(".")
let googleIndexHTML = await getGoogleIndexHTML(url)
await fs.writeFile(directory + '/' + a[1] + '.html', googleIndexHTML, (err) => {
if (err) throw err
})
console.log('File created.')
} catch (err) {
console.log(err)
}
}
const html_to_zip_file = async () => {
await zipper.zip(directory, function (error, zipped) {
if (!error) {
zipped.compress();
zipped.save('./package.zip', function (error) {
if (!error) {
console.log("Saved successfully !");
}
});
} else {
console.log(error)
}
})
}
const send_mails = async () => {
while (stack.length > 0) {
isFunctionRunning = true
var a = stack.shift()
var urls = a[0]
var collection_urls = urls.split(",");
var to_email = a[1]
rimraf(directory, function () {
console.log("done");
});
fs.mkdirSync(directory);
for (url of collection_urls) {
await some_function_to_download(url); // 5 sec per download
}
await html_to_zip_file() // takes 5 sec to zip
.then(result => {
transporter.sendMail(set_mail_options(to_email)) //2 sec to send mail
.then(result => {
console.log("Mail sent")
})
.catch(err => {
console.log(err)
})
})
.catch(err => {
console.log(err)
})
console.log("reached") // this is reached before zip is done and mail sent. I want to prevent this
}
isFunctionRunning = false
}
You need to return transporter.sendMail in sendMail, fs.writeFile in someFunctionToDownload and zipper.zip in htmlToZipFile otherwise the await won't work as expected (I'm assuming that they actually do return promises, I'm only familiar with fs.writeFile)
Also: CamelCase is used in JS, not snake_case 🙃
And are you sure rimraf is synchronous?
const sendMails = async () => {
while (stack.length > 0) {
isFunctionRunning = true;
const [urls, toEmail] = stack.shift();
var collectionUrls = urls.split(",");
rimraf(directory, function() {
console.log("done");
});
await fs.mkdir(directory);
await Promise.All(collectionUrls.map(someFunctionToDownload)); // 5 sec per download
await htmlToZipFile() // takes 5 sec to zip
.then(result => transporter.sendMail(set_mail_options(toEmail))) //2 sec to send mail
.then(result => {
console.log("Mail sent");
})
.catch(err => {
console.log(err);
});
console.log("reached"); // this is reached before zip is done and mail sent. I want to prevent this
}
isFunctionRunning = false;
};
const someFunctionToDownload = async url => {
const a = url.split(".");
const googleIndexHTML = await getGoogleIndexHTML(url);
return fs.writeFile(`${directory}/${a[1]}.html`, googleIndexHTML, err => {
if (err) throw err;
});
};
const htmlToZipFile = async () => {
return zipper.zip(directory, function(error, zipped) {
if (!error) {
zipped.compress();
zipped.save("./package.zip", function(error) {
if (!error) {
console.log("Saved successfully!");
}
});
} else {
console.log(error);
}
});
};
Try using the following
while (stack.length > 0) {
isFunctionRunning = true
var a = stack.shift()
var urls = a[0]
var collection_urls = urls.split(",");
var to_email = a[1]
rimraf(directory, function () {
console.log("done");
});
fs.mkdirSync(directory);
for (url of collection_urls) {
await some_function_to_download(url); // 5 sec per download
}
try {
const result = await html_to_zip_file() // takes 5 sec to zip
const sendMailResult = await transporter.sendMail(set_mail_options(to_email))
} catch(e)
{
console.log(e)
}
console.log("reached")
}
Since html_to_zip_file() and sendMail function are independent
we can use
const result = await Promise.all([html_to_zip_file(),transporter.sendMail(set_mail_options(to_email))]);

How to run a Node script

I need to be able to run a node script to delete an object from an external API. So I should be able to run this command:
node server.js Customer55555
And it should delete the object.
I have called to the API by using Axios.
const axios = require("axios");
const API = "http://dummy.restapiexample.com/api/v1/employees";
function getAllEmployees() {
axios
.get("http://dummy.restapiexample.com/api/v1/employees")
.then(response => {
// console.log(response.data);
console.log(response.status);
function filterEmployee() {
const employeeData = response.data;
employeeData.filter(employee => {
console.log(employee);
});
// console.log(employeeData);
}
filterEmployee();
})
.catch(error => {
console.log(error);
});
}
function deleteEmployee() {
axios({
method: "DELETE",
url: "http://dummy.restapiexample.com/api/v1/delete/36720",
headers: { "Content-Type": "application/json" }
})
.then(
// Observe the data keyword this time. Very important
// payload is the request body
// Do something
console.log("user deleted")
)
.catch(function(error) {
// handle error
console.log(error);
});
}
// getAllEmployees();
deleteEmployee();
I am able to get an individual object, but I need to figure out how to delete it by running the command above.
You can do something like this:
const axios = require("axios")
const API = "http://dummy.restapiexample.com/api/v1/employees"
async function getAllEmployees(filter = null) {
try {
const response = await axios.get("http://dummy.restapiexample.com/api/v1/employees")
console.log(response.status)
let employeeData = response.data
if (filter) {
// return only employees whose name contains filter.name
employeeData = employeeData.filter(({ employee_name }) => {
return employee_name.toLowerCase().indexOf(filter.name.toLowerCase()) >= 0
})
}
return employeeData
} catch(error) {
console.error(error)
return []
}
}
async function deleteEmployee({ id }) {
if (!id) {
throw new Error('You should pass a parameter')
}
try {
const response = await axios({
method: "DELETE",
url: `http://dummy.restapiexample.com/api/v1/delete/${id}`,
headers: { "Content-Type": "application/json" }
})
console.log("user deleted " + id)
} catch(error) {
// handle error
console.error(error)
}
}
async function main(params) {
const employees = await getAllEmployees({ name: params[0] || '' })
// Returns a promise to wait all delete promises
return Promise.all(employess.map(employee => deleteEmployee(employee)))
}
// process.argv contains console parameters. (https://stackoverflow.com/questions/4351521/how-do-i-pass-command-line-arguments-to-a-node-js-program)
main(process.argv.slice(2)).then(() => {
// returns 0 (Success) (https://stackoverflow.com/questions/5266152/how-to-exit-in-node-js)
process.exit(0)
}).catch(() => {
// returns 1 (error)
process.exit(1)
})
You should adapt this sample to get proper filtering and error reporting.

Implement callbacks between two actions in redux

I'm new to react,I'm revamping my web application from angular to react. I've got stuck at this particular point. My application requires a token to perform API calls. when a token expires on a particular API call,I watch for the failure case and run a refresh token call,On the success of refresh token call i rerun that particular API. it was simple to implement in angular but i just can not figure out in react redux.
here is my angular code
var fetchAccessToken = function(successCallback,failureCallback){
if($cookies.get('aid')){
accountGetATAPI.save({
a_id : $cookies.get('aid'),
d_id : window.fingerprint.md5hash,
at : getAt(),
cl : "W",
rt : getRefreshToken(),
k_ey : getSecret()
},function (res) {
var at = res.data.at;
//console.log("server received token: " + at);
$cookies.put('at',res.data.at);
successCallback(res);
},function (res) {
failureCallback(res);
});
}
};
var fetchProfiles = function(successCallback,failureCallback,currentTry,maxTry) {
var aid = data["Account"]["_id"];
accountProfileFetchAPI.save({
a_id : getAccountId(),
tokn : getAt()
},function(res){
data["Profiles"] = res["data"]["Profile"];
//200
successCallback(res);
},function(res){
//not 200
if(res.status == error_constants.TOKEN_EXPIRE_CODE) {
fetchAccessToken(function(){
if(currentTry < maxTry) {
fetchProfiles(successCallback, failureCallback, ++currentTry, maxTry);
} else {
console.log("maximum tries exceeded");
}
},function(res){
if(res.status == (error_constants.TOKEN_EXPIRE_CODE || error_constants.TOKEN_ERROR_CODE)){
failureCallback(error_constants.LOGOUT_USER,res);
}
});
} else {
failureCallback(null,res);
}
});
};
I'm trying to do something similar in react code. till now i only have reached till here. i know the code is crap. but im still figuring out!
export function fetchProfiles(currentTry,maxTry) {
return function(dispatch) {
axios.post("/profile/find",{
a_id : cookies.load("aid"),
tokn : cookies.load("at")
}).then((response) => {
console.log(response);
dispatch({type: "FETCH_PROFILES_FULFILLED", payload: response.data.data})
})
.catch((err) => {
console.log(err)
if(err.response.status == 498){
fetchAccessToken((res) =>{
if(currentTry < maxTry) {
console.log("at successcall ",currentTry,maxTry);
fetchProfiles(++currentTry, maxTry);
} else {
console.log("maximum tries exceeded");
}
console.log(res);
},(err) =>{
console.log(err);
});
return;
}
dispatch({type: "FETCH_PROFILES_REJECTED", payload: err})
})
}
}
export function fetchAccessToken(successCallback,failureCallback){
axios.post("/account/g_at_w",{
a_id : cookies.load('aid'),
d_id : window.fingerprint.md5hash,
at : cookies.load('at'),
cl : "W",
rt : cookies.load('rt'),
k_ey : cookies.load('secret')
}).then((response) => {
console.log(response);
successCallback(response);
// dispatch({type: "FETCH_PROFILES_FULFILLED", payload: response.data.data})
})
.catch((err) => {
console.log(err.response);
failureCallback(err);
// dispatch({type: "FETCH_PROFILES_REJECTED", payload: err})
})
}
im using redux thunk and axios to perform my api calls. any help is very much appreciated.

Categories