I'm currently struggling to get variable values from one node.js module into another. This is my current problem:
I am fetching data from a REST API via https-request:
// customrequest.js
sendRequest( url, function( data, err ) {
if(err) {
console.log('--- Error ---');
console.log( err );
}
else {
console.log('--- Response ---');
console.log(data);
// output: data
return data;
}
module.exports = { sendRequest }
And my index.js file:
// index.js
let sendRequest = require('./customrequest');
let req;
req = sendRequest('google.com');
console.log(req);
// output: undefined
// how can I get the variable set, when request is getting data in response?
I totally understand, that the request to an API takes some time for the response. One solution is, that I just put everything into one js file. But as my project will get bigger over time, the modular approach is my goto-solution. Any suggestions on how to solve this?
Node uses callbacks for this situation. Try something like this:
// customrequest.js
sendRequest(url, callback)
module.exports = { sendRequest }
// index.js
let sendRequest = require('./customrequest');
let req = sendRequest('google.com', function (data, err) {
if (err) {
//handle error here
}
console.log(data);
};
// output: undefined
// how can I get the variable set, when request is getting data in response?
Thanks. The problem I encounter is somewhat different. I solved it with this code snippets … using async and await.
// request.js
const fetch = require('node-fetch')
async function myRequest (somestring) {
try {
let res = await fetch('https://api.domain.com/?endpoint='+somestring)
if (res.ok) {
if (res.ok) return res.json()
return new Error (res.status)
}
} catch (err) {
console.error('An error occurred', err)
}
}
module.exports = { myRequest }
// index.js
const request = require('./requests')
const myRequest = request.myRequest
let myVar;
myRequest('somestring')
.then(res => myVar = res.result)
setInterval(() => {
myRequest('somestring')
.then(res => myVar = res.result)
console.log(myVar)
}, 1000)
The async function and awaits return a promise. This promise is, when resolved, assigned to a variable.
Related
Summary: creating my own API that returns epoch time, and it involves using an express.js server, but it's running res.send() before the function call. I referenced this page, but it didn't help. Here's what I have:
app.get('/timestampAPI', async (req, res,) => {
try {
let finalResult = await getTimeStamp();
res.send({ something: finalResult });
} catch (error) {
console.log(error);
}
});
It'll start to run the function getTimeStamp(), and before that function finishes, it runs the res.send() function which shows up as '{}' because finalResult doesn't have a value. getTimeStamp() is an async function. I'm unsure of what I'm doing wrong.
Edit:
getTimeStamp() function:
async function getTimeStamp() {
await axios.get('https://showcase.api.linx.twenty57.net/UnixTime/tounixtimestamp?datetime=now')
.then(response => {
// also used console.log(response.data.UnixTimeStamp), which returns the timestamp
return response.data;
})
.catch(error => {
var errorMessage = error.response.statusText;
console.log(errorMessage);
});
}
Another edit: yes, the API referenced above does return the current epoch time, but CORS is blocking my other site from accessing it directly, so I can't use it on that site, which is why I'm using node.js for it so that I can allow myself to access it through my node.js program. Couldn't think of another way
returning value of the then method does not return from getTimeStamp function you should write you code in resolve pattern or using await like below
try this, make sure you write correct field name in response object
async function getTimeStamp() {
try{
const res = await axios.get('https://showcase.api.linx.twenty57.net/UnixTime/tounixtimestamp?datetime=now')
return res.data
}catch(error){
throw error
}
As an alternative to Mohammad's answer you can also use returning getTimeStamp function's result as a promise and it can solve your problem.
async function getTimeStamp() {
return new Promise((resolve, reject) => {
axios.get('https://showcase.api.linx.twenty57.net/UnixTime/tounixtimestamp?datetime=now')
.then(response => {
// also used console.log(response.data.UnixTimeStamp), which returns the timestamp
resolve(response.data);
})
.catch(error => {
var errorMessage = error.response.statusText;
console.log(errorMessage);
reject(error);
});
})
}
Or you would also replace await with return in getTimeStamp function in your code if you don't want to return promise.(Which is not I recommend.). You should also throw the error in catch block which is generated in getTimeStamp function for catching the error in try-catch block that you use to call app.get(...).
I am trying to call my rest api endpoint in AIRTABLE from inside an AWS Lambda with no success. I get no errors, no outputs.
If I call the same code using node - it works.
I am able to use Axios in my code.
Pure airtable code (works)
var Airtable = require('airtable');
var base = new Airtable({apiKey: 'keyoMYSECRETKEY'}).base('Mybaseid');
base('MyBase').select({maxRecords: 3,view: "MyView"}).eachPage(function page(records, fetchNextPage) {
// This function (`page`) will get called for each page of records.
records.forEach(function(record) {
console.log('Retrieved',JSON.stringify(record.get('Session Information')));
});
fetchNextPage();
}, function done(err) {
if (err) { console.error(err); return; }
});
If I put it inside a Lambda handler - I get nothing.
const axios = require('axios')
const url = 'https://checkip.amazonaws.com/';
var Airtable = require('airtable');
var base = new Airtable({apiKey: 'keySECRETKEY'}).base('MYBASEID');
let response;
exports.lambdaHandler = async (event, context) => {
try {
base('MyBase').select({maxRecords: 3,view: "MyView"}).eachPage(function page(records, fetchNextPage) {
records.forEach(function(record) { //HERE - NOTHING HAPPENS
console.log('Retrieved',JSON.stringify(record.get('Session Information')));
});
fetchNextPage();
}, function done(err) {
if (err) { console.error(err); return; }
});
const ret = await axios(url); //THIS WORKS
response = {
'statusCode': 200,
'body': JSON.stringify({
message: 'hello world - boo',
location: ret.data.trim()
})
}
} catch (err) {
console.log(err);
return err;
}
return response
};
What am I missing so I can call Airtable API from inside an AWS Lambda?
It seems that your lambda terminates before the API call execution your trying to perform.
I believe this will be solved using a synchronous lambda or with a correct usage of promises with await calls.
Best way to troubleshoot this is to go back to the basics.
See if you can at least get a meaningful console log by wrapping a simpler fetch request into a lambda handler:
const baseId = 'exampleAppId123';
const tableName = 'Table 1';
const api_key = 'keyExample123';
const url = `https://api.airtable.com/v0/${baseId}/${tableName}?api_key=${api_key}`;
exports.lambdaHandler = async () => {
const res = await fetch(url)
.then(res => res.json())
.then(data=>console.log(data))
.then(() => {
//do more stuff
})
}
Then report back if you can't. Or better yet, report back either way as that's bound to help more people in the future.
Worst case? The above code still doesn't do anything. If that happens, I suggest going with #Shoty's first instinct and turning this code into a synchronous fetch request by removing the async/await syntax and returning chained thenables. Not that blocking behavior of this sort is acceptable from a UX perspective, but it should at least help with debugging.
I am trying to extract data from an Axios call in Javascript. I can see that the data is being called successfully if I console.log() while inside of this block
Here is a link to a screenshot of console.log() if it is inside the axios call. https://imgur.com/a/ZLXnE2n
This data is correct, but I can't access it outside of the axios call.
const response = await axios
.get(url, config)
.then(function(response) {
data = response.data;
console.log(data)
})
However, I am unable to do anything with the data outside of the getRide_Uber function. How do I extract the response object to use in other parts of my code?
const axios = require("axios");
// Use the Uber API to estimate the cost between two
// locations specified via latitude and longitude coordinates.
getRide_Uber = async (addressOrigin, addressDestination) => {
let origin = await geocodeAddress(addressOrigin);
let destination = await geocodeAddress(addressDestination);
const url = "https://api.uber.com/v1.2/estimates/price";
const config = {
headers: {
Authorization: `Token ${process.env.UBER_SERVER_TOKEN}`
},
params: {
start_latitude: origin.lat,
start_longitude: origin.lon,
end_latitude: destination.lat,
end_longitude: destination.lon
}
};
const response = await axios
.get(url, config)
.then(function(response) {
data = response.data;
return data;
})
.catch(function(error) {
console.log(error);
});
return response;
};
// Initial code
// const rideData = getRide_Uber("Arlington Texas", "Fort Worth Texas");
// const ridePrices = rideData.prices;
// console.log(ridePrices);
// Code suggestion by #mralanlee
const a = (async() => {
const result = await getRide_Uber(start, dest);
return result;
})();
console.log(a); // Console just says <pending>
const prices = a.prices // undefined
Please let me know if anything needs clarification and I will be happy to explain. Thanks!
The data store is back into getRide_Uber.
You can have it accessible or returned globally like:
(async() => {
const result = await getRide_Uber(start, dest);
// or console.log(result)
return result;
})()
or
const a = (async() => {
const result = await getRide_Uber(start, dest);
return result;
})();
For the above solution, you would need to have this in a scape of another async function. This will not work at the global level because logging the result will not wait for the Promise to resolve. You must wrap it into an async function and await the anonymous function.
Edit: Clarification to add more clarity...
To use the 2nd solution, you could do the following:
// this async function wraps around your code, we'll call it something for a lack of a better name
// start and dest params are passed into getRide_Uber
async function something(start, dest) {
const result = await getRide_Uber(start, dest);
// You can make sure you have the resolved data here.
// console.log(result.prices)
return result;
};
// now call the function
something(start, dest);
I am learning to use async / await and am having issues when trying to make an api request to set up my twilio device. Given the below code block, when I call device(), I get the following error message:
Uncaught
TwilioException {message: "Capability token is not valid or missing."}
message
:
"Capability token is not valid or missing."
__proto__
:
Object
I believe this is due to the fact that the json returned in the device function is still shown as pending. How do I resolve this and what am I doing wrong? Thanks.
Code block:
import {Device} from 'twilio-client';
const api = async () => {
try {
const response = await fetch('/api/twilio');
const json = await response.json();
if (response.status === 403) {
twilioConnectionFailure('Twilio has not been purchased.');
}
return json;
} catch (error) {
console.log(`Connection failed: ${error.message}`);
throw Error(error.message);
}
};
const device = () => {
const json = api();
Device.setup(json.token);
return Device;
};
export default device;
The api function is still asynchronous and returns a promise - you need to wait for it:
export default async function device() {
const json = await api();
// ^^^^^
Device.setup(json.token);
return Device;
}
I am trying to make a simple weather application based on Node.js, like this one. My problem is that every mechanism I see is based on promises, and I don't understand the concept.
So, the code I see everywhere is like:
yrno.getWeather(LOCATION).then((weather) => {
weather.getFiveDaySummary().then((data) => console.log('five day summary', data));
weather.getForecastForTime(new Date()).then((data) => console.log('current weather', data));
})
.catch((e) => {
console.log('an error occurred!', e);
});
However, I was unable to find a way to resolve these promises and save the five day summary to a variable for later use.
How do I proceed?
Thanks,
Robin
Assign the Promise returned from yrno.getWeather(LOCATION) call to a variable.
Use Promise.all() to return results from both weather.getFiveDaySummary() and weather.getForecastForTime(new Date()) calls.
Chain .then() to the result of call to get the data at initial and subsequent .then() chained to variable identifier which returned initial Promise values.
let weatherData = yrno.getWeather(LOCATION).then(weather => {
// note `return`, alternatively omit `return` and `{`, `}` at arrow function
// .then(weather => Promise.all(/* parameters */))
return Promise.all([weather.getFiveDaySummary()
, weather.getForecastForTime(new Date())]);
});
weatherData
// `results` is array of `Promise` values returned from `.then()`
// chained to `yrno.getWeather(LOCATION).then((weather)`
.then(results => {
let [fiveDaySummary, forecastForTime] = results;
console.log('five day summary:', fiveDaySummary
, 'current weather:', forecastForTime);
// note `return` statement, here
return results
})
.catch(e => {
// `throw` `e` here if requirement is to chain rejected `Promise`
// else, error is handled here
console.log('an error occurred!', e);
});
// weatherData
// .then(results => { // do stuff with `results` from first `weatherData` call })
// .catch(e => console.log(e));
An alternative to using promises directly is to use await/async.
// weather.js
const yrno = require('yr.no-forecast')({
version: '1.9', // this is the default if not provided,
request: {
// make calls to locationforecast timeout after 15 seconds
timeout: 15000
}
});
const LOCATION = {
// This is Dublin, Ireland
lat: 53.3478,
lon: 6.2597
};
async function getWeather() {
let weather = await yrno.getWeather(LOCATION);
let fiveDaySummary = await weather.getFiveDaySummary();
let forecastForTime = await weather.getForecastForTime(new Date());
return {
fiveDaySummary: fiveDaySummary,
forecastForTime: forecastForTime,
}
}
async function main() {
let report;
try {
report = await getWeather();
} catch (e) {
console.log('an error occurred!', e);
}
// do something else...
if (report != undefined) {
console.log(report); // fiveDaySummary and forecastForTime
}
}
main(); // run it
you can run this (node.js 7) with:
node --harmony-async-await weather
You can use await/async on older targets by using Babel or Typescript to transpile it down for you.
Bonus (based off your comments) - I wouldn't do it this way, but just to show you it can be done:
const http = require('http');
const port = 8080;
http.createServer(
async function (req, res) {
let report = await getWeather(); // see above
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("" + JSON.stringify(report.fiveDaySummary));
res.end('Hello World\n');
})
.listen(port);
again with node --harmony-async-await weather or transpile it.