i'm new in Node.js, I'm trying to use a variable declared within a Request, but I need to use it outside the Request.Is this possible?.
Sample code:
//stackExample
var request = require('request')
cheerio = require('cheerio')
jsonArr = []
request ({
url: 'http://youtube.com',
encoding: 'utf8'
},
function (err, resp, body){
if(!err && resp.statusCode == 200){
var $ = cheerio.load(body);
$('.yt-lockup-title').each(function(){
var title = $(this).find('a').text();
jsonArr.push({
titulo: title,
});
});
}
console.log(jsonArr) //Here Works!
}
);
console.log(jsonArr) //Here not :(, I need works here :'(
Your jsonArr variable only works inside your request function because this wait for the url response, while your outside console.log its executed line by line. You can create a function that will be called inside your anonymous function to use it outside the request function.
var request = require('request')
cheerio = require('cheerio')
jsonArr = []
request ({
url: 'http://youtube.com',
encoding: 'utf8'
},
function (err, resp, body){
if(!err && resp.statusCode == 200){
var $ = cheerio.load(body);
$('.yt-lockup-title').each(function(){
var title = $(this).find('a').text();
jsonArr.push({
titulo: title,
});
updated()
});
}
console.log(jsonArr)
}
);
function updated(){
console.log(jsonArr)
}
The issue with above code is that the value in jsonArr is pushed when the request returns from the http call and then injects the value into jsonArr.
You would want to access the value of jsonArr after that call returns.Which you can do by using promises.
Or just a hack using setTimeout.
setTimeout(function(){
console.log(jsonArr); // use value after time interval
},1000); // you can set this value depending on approx time it takes for your request to complete.
Or use the defered function libraries refer this.
var sequence = Futures.sequence();
sequence
.then(function(next) {
http.get({}, next);
})
.then(function(next, res) {
res.on("data", next);
})
.then(function(next, d) {
http.get({}, next);
})
.then(function(next, res) {
...
})
You need to wrap the console.log in a callback as follows.
The following code will log [5]
var jsonArry = [];
var test = function(num, callback){
jsonArry.push(num);
callback(jsonArry);
};
test(5, function(data){
console.log(data);
});
Related
I have an application in Node with Express and trying to successfully finish the implementation of a payment system called "Flow".
[EDIT]
I bypassed something very important, it's a function that wraps the functionality that is triggering after the end of the method. I tried making it async so I can wrap the functions then as a promise like someone adviced, but got some errors. I'll re-check.
//REALIZAR PAGO $
app.post('/realizarPago', function(req, res){
var amount = Math.floor(Math.random() * 999999) + 100000;
var paymentMethod = 9;
var urlRedirect = "https://sandbox.flow.cl/app/web/pay.php?token=";
...
//Other relevant variables
var req = https.request(options, function (res) { //<=== This one
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
...
//this is just a sample token that I'll later capture from response
urlRedirect = urlRedirect+"1234567890";
});
});
var postData = qs.stringify({
'flowOrder': flowOrder,
'amount': amount,
...
});
req.write(postData);
res.redirect(307, urlRedirect);
req.end();
});
Everything works almost fine, the problem is that the redirect is executed before urlRedirect updates its value in urlRedirect = urlRedirect+"1234567890";
I've tried with .then() after res.write(postData) executes, with no useful result. I've tried .then() in almost every method, I've also tried with res instead of req and viceversa. I also did some research and found an interesting thing called "waterfall" for async methods but in case of res.on methods can't imagine a way of encapsulating this.
What can I try next?
[EDIT 2]
Thanks to all of your guidance, I was able to use some promises and change the execution order. Now it's doing what I need, now it says that some parameters are missing in the https request. I'll have to fix that. The final code is:
//REALIZAR PAGO $
app.post('/realizarPago', async function(request, response){
var amount = Math.floor(Math.random() * 999999) + 100000;
var paymentMethod = 9;
...
//Other relevant variables
var urlRedirect = "https://sandbox.flow.cl/app/web/pay.php?token=";
var req = https.request(options, (res) => {
var chunks = [];
res.on("data", (chunk) => {
chunks.push(chunk);
});
res.on("end", (chunk) => {
var body = Buffer.concat(chunks);
var datos = body.toString();
datos = JSON.parse(datos);
var token = datos.token;
urlRedirect = urlRedirect+token
response.redirect(urlRedirect);
});
});
req.end();
var postData = qs.stringify({
'flowOrder': flowOrder,
'amount': amount,
...
});
req.write(postData);
req.end();
});
You put the redirect into the end event handler, and you also add an error handler in case the request fails and you change the name of one of the two res arguments so they don't conflict and you can still access both of them. I changed the higher level one to response so it can be used inside the other callbacks where res is already defined:
//REALIZAR PAGO $
app.post('/realizarPago', function(req, response){ // <== change arg name to response
var amount = Math.floor(Math.random() * 999999) + 100000;
var paymentMethod = 9;
var urlRedirect = "https://sandbox.flow.cl/app/web/pay.php?token=";
...
//Other relevant variables
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
...
//this is just a sample token that I'll later capture from response
urlRedirect += "1234567890";
response.redirect(307, urlRedirect); // <== move this here
});
});
req.on('error', err => { // <== add this
console.log(err);
response.sendStatus(500);
});
var postData = qs.stringify({
'flowOrder': flowOrder,
'amount': amount,
...
});
req.write(postData);
req.end();
});
I want to parse body outside of request. But i can not figure out a way to get it outside of the request function. Can you please show me how? Or at least give me an example. I do not understand it.
"use strict"
var robotsParser = require('robots-parser');
var request = require('request');
var fs = require('fs')
let url = 'http://google.de/robots.txt'
request(url, function(error, response, body) {
//console.log(body)
robots = robotsParser(url, body)
var reserveisDisallowed = robots.isDisallowed('http://google.de/maps/reserve/api/', '*')
console.log(reserveisDisallowed)
})
Use jQuery deferred, if you want to execute this instruction after success callback as:
var $deferred = $.Deferred(),
robots,
globalBody;
$deferred.done(function(body){
robots = robotsParser(url, body);
globalBody = body; //After here globalBody object has body available. Do whatever you want to do now.
var reserveisDisallowed = robots.isDisallowed('http://google.de/maps/reserve/api/', '*')
console.log(reserveisDisallowed)
});
request(url, function(error, response, body) {
//console.log(body)
$deferred.resolve(body);
})
or if U just want body available outside, simply use 'globalBody' variable in your code
As:
request(url, function(error, response, body) {
//console.log(body)
robots = robotsParser(url, body);
globalBody = body;
var reserveisDisallowed = robots.isDisallowed('http://google.de/maps/reserve/api/', '*')
console.log(reserveisDisallowed)
})
I'm fairly new to Node and Javascript and I'm struggling with my first Node module. What I'm trying to do is export functions for specific API calls and I'd like to reuse my https.request function rather than duplicating the code in each function. For some reason I'm failing to wrap my head around how to pass the data back to my original function. Here's an abbreviated version - the listStuff function would be one of many to handle various api request actions.
'use strict';
const https = require('https');
const _ = require('underscore');
const hostStr = 'api.server.net';
function listStuff(){
var pathStr = '/release/api/stuff';
_apiCall(pathStr);
//Would like to handle the https response data here
};
function _apiCall(pathStr){
var options = {
host: hostStr,
path: pathStr
};
var req = https.get(options, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
var responseString = '';
res.on('data', function(d){
responseString += d;
});
res.on('end', function(){
var responseObject = JSON.parse(responseString);
});
});
req.end();
req.on('error', function(e){
console.log(e);
});
};
module.exports = {
listStuff: listStuff
};
Hope this helps. Register a callback in the apiCall function, and then check the callback params for error handling. Then, just make sure you return the callback when you want to end the function call (either in the on end or on error processing).
function listStuff(){
var pathStr = '/release/api/stuff';
_apiCall(pathStr, function(err, data) {
if (err) // handle err
//handle data.
});
};
function _apiCall(pathStr, callback){
var options = {
host: hostStr,
path: pathStr
};
var req = https.get(options, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
var responseString = '';
res.on('data', function(d){
responseString += d;
});
res.on('end', function(){
var responseObject = JSON.parse(responseString);
return callback(null, responseObject);
});
});
req.end();
req.on('error', function(e){
console.log(e);
return callback(e);
});
};
A slightly different approach using Promise objects. Note I looked into this as a learning exercise and hope it helps. I have not written all the code for you and the debugging is all yours!
Firstly make _apiCall returns a promise object.
function listStuff()
{
var pathStr = '/release/api/stuff';
var promise = _apiCall(pathStr);
promise.then( function( responceObject){
// handle response object data
});
promise.catch( function( error){
console.log( error.message); // report error
});
}
Next step is to make _apiCall return a promise object for the HTTPS request it will initiate inside the executor of promise creation.
function _apiCall(pathStr)
{ var options = {
host: hostStr,
path: pathStr
};
function beginGet( worked, failed)
{
// see below
}
return new Promise( beginGet);
}
Lastly write beginGet to initiate and call back success or fail functions depending on the outcome of the get request.
function beginGet( worked, failed)
{ var req;
var responseObj;
function getCallBack( res)
{ // all your get request handling code
// on error call failed( error)
// on sucessful completion, call worked(responseObj)
}
req = https.get(options, getCallBack);
}
Also please check with https.get documentation - I think it calls req.end() for you. All the other errors are mine :-)
Goal: (solved: updated working code below)
Create an array of urls
Create a function that accepts a single url, makes a request to that url, and writes some data to file
Run above function in series multiple times for each url in the array.
Node Dependencies: Request, Cheerio, async, fs
Here is what I have so far:
//load dependencies
var request = require("request"),
cheerio = require("cheerio"),
fs = require('fs'),
async = require('async'),
wstream = fs.createWriteStream('./model/data.txt');
//create url array
var arr = [];
for (var i = 0; i < 10; i++){
arr.push('http://www.test.com/' + i)
}
//function that gets data from url and creates write stream
function getUrlData(url, callback){
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(body);
var data = $('h1').html();
wstream.write(data);
callback();
}
});
}
//close write stream
function endStream(){
wstream.end();
}
//updated working version
async.eachSeries(arr,getUrlData,endStream);
Since you want getUrlData to be executed sequentually, you'll need to add a callback to getUrlData:
function getUrlData(url, callback){
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(body);
var data = $('h1').html();
wstream.write(data);
callback();
}
callback(error);
});
}
Then use eachSeries:
async.eachSeries(arr, getUrlData, endStream);
I am trying to make a function that returns the content of the webpage and this is what I have so far
var get_contents = function() {
var httpRequestParams =
{
host: "google.com",
port: 80,
path: "/?"
};
var req = http.get(httpRequestParams, function(res)
{
var data = '';
res.on('data', function(chunk) {
data += chunk.toString();
});
//console.log(data);
}).end();
return req;
}
This when I run this code, I see the html contents when the console logging is turned on but when I try to return the output, it just never works.
I can't figure out a way to return get_contents() anywhere. On the console, it just doesnt respond.
Thanks
Something like that: (dont forget to handle error and timeout)
var on_contents = function(cb) {
var httpRequestParams =
{
host: "google.com",
port: 80,
path: "/?"
};
var req = http.get(httpRequestParams, function(res)
{
var data = '';
res.on('data', function(chunk) {
data += chunk.toString();
});
res.on('end', function(){
cb(data);
});
//console.log(data);
}).end();
}
function onFinish(data) {
console.log(data);
}
on_contents(onFinish)
The short answer is: You can't return the data from that function. http.get is asynchronous, so it doesn't actually start running the callback until after your function ends. You'll need to have your get_contents function take a callback itself, check in the http.get handler whether you're done loading and, if you are, call the get_contents callback.
There is an awesome module [request][1] available in node.js.
var request = require('request'),
url = require('url');
var server = http.createServer(function (request, response) {
getPage("http://isohunt.com/torrents/?iht=-1&ihq=life+is+beautiful", function (body) {
console.log(body);
})
});
server.listen(3000);
More information can be found on http://www.catonmat.net/blog/nodejs-modules-request/