I'm using the request library in Node.js to do a https request to get data from another service. This is called asynchronously, right? So my code keeps running before all of the data is there, correct?
My problem is that the data is needed right afterwards to calculate some things. My code throws an error during that calculation because the data from the service is undefined...
Could it be possible that the data is just not there yet? And if so, what do you do against that?
Here is a copy of the request:
const request = require('request');
request(someUrl, {"Accept": "application/json"}, (err, res, body) => {
if (err)
handleError(err);
body = JSON.parse(body);
return body;
});
This kind of situation is pretty common in react/angular/vue kinda web apps, sometimes you need the data right away. But it is not available then, after a Rest call or something it becomes available.
So, the simplest solution?
Just add a check, for example:
const calculate = (someVal)=>{
if(!someVal) return ;
//otherwise do the calculation
}
There are plenty of other ways, by mostly making the calculation async. For your function, you can do this
const promOp = function(){
return new Promise((resolve, reject) => {
request(someUrl, {"Accept": "application/json"}, (err, res, body) => {
if (err) reject(err);
body = JSON.parse(body);
resolve(body);
});
}
}
//then
promOp()
.then((body)=>{
//calculate here
})
//or can use the `Async/Await` syntax instead of then
const op = async () => {
const body = await promOp;
//calculate here
}
Related
I fetch data at server side and push the result to global variable and then send that global variable to client with app.post method using Express.js. My problem is that client fetches the global variable too soon without the data received from the API first. How can I evaluate the response so that client would wait the global variable to reveive data first before displaying anything.
Server side, code looks something like this:
let sharpe = ''
app.post('/api', async(req, res, next) => {
console.log('I got a request!')
thisOne = req.body.stock1
thisOne2 = req.body.stock2
var result = await setup();
res.json({
status: 'success',
stocks: sharpe
});
})
Sharpe is the global variable storing the response from multiple API calls and is the one that should be sent back to client. Client side code is this:
const sendData = async (event) => {
event.preventDefault();
var stock1 = document.getElementById('weight1').value
var stock2 = document.getElementById('weight2').value
const data = {stock1, stock2};
const options = {
method: 'POST',
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json' }
}
fetch('/api', options).then(res => res.json()).then(res => {
console.log(res.stocks);
})
}
As a result SendData() function fetches the sharpe variable that is empty at the moment. How can I adjust client side code or server side code that the client waits for a correct response? Thanks.
One solution would be to store the API results to database and client would fetch ready made datastream but is there more straightforward solution?
To wait for your API Server to set the sharpe Parameter, it needs to be awaited, which you already did. It depends on the setup function (for example setup()) which fills the sharpe parameter. It has to return a promise, which is resolved once sharpe is filled with the data.
let sharpe = ''
async setup() {
return new Promise((resolve, reject) => {
sharpe = 'test';
// set value for sharpe
resolve()
})
}
app.post('/api', async(req, res, next) => {
console.log('I got a request!')
thisOne = req.body.stock1
thisOne2 = req.body.stock2
var result = await setup();
res.json({
status: 'success',
stocks: sharpe
});
})
Eventually it starded working when I pushed all the API calls in the app.post middleware at the server side using promise chaining. The initial problem remains a mystery.
I am trying to store the response of an http request made using nodejs by request module but the problem is I can't acsess it after the request is completed in more details we can say after the callback
How I can add it
Here is what I tried till now
Tried to use var instead of let
Tried passing it to a function so that i can use it later but no luck
Here is my code can anyone help actually new to nodejs that's why maybe a noob question
var request = require('request')
var response
function sort(body) {
for (var i = 0; i < body.length; i++) {
body[i] = body[i].replace("\r", "");
}
response = body
return response
}
request.get(
"https://api.proxyscrape.com/?request=getproxies&proxytype=http&timeout=10000&country=all&ssl=all&anonymity=all",
(err, res, body) => {
if (err) {
return console.log(err);
}
body = body.split("\n");
sort(body);
}
);
console.log(response)
In this I am fetching up the proxies from this api and trying to store them in a variable called as response
var request = require("request");
var response;
async function sort(body) {
await body.split("\n");
response = await body;
console.log(response); // this console log show you after function process is done.
return response;
}
request.get(
"https://api.proxyscrape.com/?request=getproxies&proxytype=http&timeout=10000&country=all&ssl=all&anonymity=all",
(err, res, body) => {
if (err) {
return console.log(err);
}
sort(body);
}
);
// console.log(response); //This console log runs before the function still on process, so that's why it gives you undefined.
Try this code it works fine I just tested.
put the console log inside the function so you can see the result.
The console.log that you put actually runs before you process the data so that's why you are getting "undefined".
Actually, you will get the data after the sort Function is done processing.
I'm quite new to Nodejs. In the following code I am getting json data from an API.
let data_json = ''; // global variable
app.get('/', (req, res) => {
request('http://my-api.com/data-export.json', (error, response, body) => {
data_json = JSON.parse(body);
console.log( data_json ); // data prints successfully
});
console.log(data_json, 'Data Test - outside request code'); // no data is printed
})
data_json is my global variable and I assign the data returned by the request function. Within that function the json data prints just fine. But I try printing the same data outside the request function and nothing prints out.
What mistake am I making?
Instead of waiting for request to resolve (get data from your API), Node.js will execute the code outside, and it will print nothing because there is still nothing at the moment of execution, and only after node gets data from your api (which will take a few milliseconds) will it execute the code inside the request. This is because nodejs is asynchronous and non-blocking language, meaning it will not block or halt the code until your api returns data, it will just keep going and finish later when it gets the response.
It's a good practice to do all of the data manipulation you want inside the callback function, unfortunately you can't rely on on the structure you have.
Here's an example of your code, just commented out the order of operations:
let data_json = ''; // global variable
app.get('/', (req, res) => {
//NodeJS STARTS executing this code
request('http://my-api.com/data-export.json', (error, response, body) => {
//NodeJS executes this code last, after the data is loaded from the server
data_json = JSON.parse(body);
console.log( data_json );
//You should do all of your data_json manipluation here
//Eg saving stuff to the database, processing data, just usual logic ya know
});
//NodeJS executes this code 2nd, before your server responds with data
//Because it doesn't want to block the entire code until it gets a response
console.log(data_json, 'Data Test - outside request code');
})
So let's say you want to make another request with the data from the first request - you will have to do something like this:
request('https://your-api.com/export-data.json', (err, res, body) => {
request('https://your-api.com/2nd-endpoint.json', (err, res, body) => {
//Process data and repeat
})
})
As you can see, that pattern can become very messy very quickly - this is called a callback hell, so to avoid having a lot of nested requests, there is a syntactic sugar to make this code look far more fancy and maintainable, it's called Async/Await pattern. Here's how it works:
let data_json = ''
app.get('/', async (req,res) => {
try{
let response = await request('https://your-api.com/endpoint')
data_json = response.body
} catch(error) {
//Handle error how you see fit
}
console.log(data_json) //It will work
})
This code does the same thing as the one you have, but the difference is that you can make as many await request(...) as you want one after another, and no nesting.
The only difference is that you have to declare that your function is asynchronous async (req, res) => {...} and that all of the let var = await request(...) need to be nested inside try-catch block. This is so you can catch your errors. You can have all of your requests inside catch block if you think that's necessary.
Hopefully this helped a bit :)
The console.log occurs before your request, check out ways to get asynchronous data: callback, promises or async-await. Nodejs APIs are async(most of them) so outer console.log will be executed before request API call completes.
let data_json = ''; // global variable
app.get('/', (req, res) => {
let pr = new Promise(function(resolve, reject) {
request('http://my-api.com/data-export.json', (error, response, body) => {
if (error) {
reject(error)
} else {
data_json = JSON.parse(body);
console.log(data_json); // data prints successfully
resolve(data_json)
}
});
})
pr.then(function(data) {
// data also will have data_json
// handle response here
console.log(data_json); // data prints successfully
}).catch(function(err) {
// handle error here
})
})
If you don't want to create a promise wrapper, you can use request-promise-native (uses native Promises) created by the Request module team.
Learn callbacks, promises and of course async-await.
I'm building an Express app using Twilio to allow a group of people to communicate via SMS without having to install an app or deal with the limitations on group texts that some phones/carriers seem to have. It's deployed via Azure, but I'm reasonably sure I'm past the configuration headaches. As an early test that I can make this work and for a bit of flavor, I am trying to set up a feature so you can text "joke" (ideally case-insensitive) and it will send a random joke from https://icanhazdadjoke.com/. If anything else is texted, for now it should basically echo it back.
I get the sense this has to do with js being asynchronous and the code moving on before the GET comes back, so I'm trying to use promises to get the code to wait, but the conditional nature is a new wrinkle for me. I've been looking for answers, but nothing seems to work. I've at least isolated the problem so the non-joke arm works correctly.
Here is the function for retrieving the joke, the console.log is outputting correctly:
const rp = require('request-promise-native');
var options = {
headers: {
'Accept': 'application/json'
}
}
function getJoke() {
rp('https://icanhazdadjoke.com/', options) //add in headers
.then(joke => {
theJoke = JSON.parse(joke).joke
console.log(theJoke)
return theJoke
});
}
}
Here is the part of my router that isn't working quite right. If I text something that isn't "joke", I get it echoed back via SMS. If I text "joke", I don't get a reply SMS, I see "undefined" in the Kudu log (from below), and then I see the log of the POST, and then afterward I see the joke from the function above having run.
smsRouter.route('/')
.post((req, res, next) => {
const twiml = new MessagingResponse();
function getMsgText(request) {
return new Promise(function(resolve, reject) {
if (req.body.Body.toLowerCase() == 'joke') {
resolve(getJoke());
}
else {
resolve('You texted: ' + req.body.Body);
}
})
}
getMsgText(req)
.then(msg => {
console.log(msg);
twiml.message(msg);
res.writeHead(200, {'Content-Type': 'text/xml'});
res.end(twiml.toString());
})
})
How can I make it so that getMsgText() waits for the getJoke() call to fully resolve before moving on to the .then?
I think this is what you're looking for.
Note that I've used async/await rather than promise chaining.
// joke.get.js
const rp = require('request-promise-native');
var options = {
headers: {
'Accept': 'application/json'
}
}
async function getJoke() {
const data = await rp('https://icanhazdadjoke.com/', options) //add in headers
return JSON.parse(data).joke;
}
// route.js
smsRouter.route('/')
.post(async (req, res, next) => {
const twiml = new MessagingResponse();
async function getMsgText(request) {
if(req.body.Body.toLowerCase() === 'joke'){
return await getJoke();
}
return `You texted: ${req.body.Body}`
}
const msg = await getMsgText(req);
twiml.message(msg);
res.status(200).send(twiml.toString());
})
async/await in JS
I have a simple node Express app that has a service that makesa call to a node server. The node server makes a call to an AWS web service. The AWS simply lists any S3 buckets it's found and is an asynchronous call. The problem is I don't seem to be able to get the server code to "wait" for the AWS call to return with the JSON data and the function returns undefined.
I've read many, many articles on the web about this including promises, wait-for's etc. but I think I'm not understanding the way these work fully!
This is my first exposer to node and I would be grateful if somebody could point me in the right direction?
Here's some snippets of my code...apologies if it's a bit rough but I've chopped and changed things many times over!
Node Express;
var Httpreq = new XMLHttpRequest(); // a new request
Httpreq.open("GET","http://localhost:3000/listbuckets",false);
Httpreq.send(null);
console.log(Httpreq.responseText);
return Httpreq.responseText;
Node Server
app.get('/listbuckets', function (req, res) {
var bucketData = MyFunction(res,req);
console.log("bucketData: " + bucketData);
});
function MyFunction(res, req) {
var mydata;
var params = {};
res.send('Here are some more buckets!');
var request = s3.listBuckets();
// register a callback event handler
request.on('success', function(response) {
// log the successful data response
console.log(response.data);
mydata = response.data;
});
// send the request
request.
on('success', function(response) {
console.log("Success!");
}).
on('error', function(response) {
console.log("Error!");
}).
on('complete', function() {
console.log("Always!");
}).
send();
return mydata;
}
Use the latest Fetch API (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make HTTP calls. It has built-in support with Promise.
fetch('http://localhost:3000/listbuckets').then(response => {
// do something with the response here
}).catch(error => {
// Error :(
})
I eventually got this working with;
const request = require('request');
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
parseString(body, function (err, result) {
console.log(JSON.stringify(result));
});
// from within the callback, write data to response, essentially returning it.
res.send(body);
}
else {
// console.log(JSON.stringify(response));
}
})