Unable to initiate the route from the beginning after else statement deadend - javascript

Firstly, I'm sorry if this has been posted before. I searched but couldn't find any credible solution.
So I'm working on this route in nodejs where I make an API call for a piece of information and then using that info in an if statement to check if it's the correct info(the server sometimes sends wrong info).
If I get the correct info then I use that in another API to get more info about it and render it into my template. Everything works fine.
But I want the first API call to take place again if the info doesn't match or it's wrong. How can I initiate the API call again from the start(like a loop) and it will break only if the info is correct. Please check the "comment" in the code below. That is where I don't know what to put. Your help would be highly appreciated.
PS. I am a beginner in nodejs and javascript.
Route
router.get("/check", (req, res) => {
if(req.query.search) {
var input = req.query.search;
var url = "http://firstapi.com/json/" + input + "?fields=query";
request(url, function(error, response, body) {
if(!error && response.statusCode === 200) {
var data = JSON.parse(body);
if(data.query.match(/((^|\.)((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))){4}$/)){
var url = "https://secondapi.com/" + data.query + "?key=something";
request(url, function(error, response, body) {
if(!error && response.statusCode === 200) {
var Data = JSON.parse(body);
res.render("index", {data: Data});
}
});
}else{
//want to use the input at the top and check the firstapi again. All the code above should run again until its the correct one which I will use in my template.
}
}
});
}else{
res.render("index", {data: null});
}
});

I would probably do it this way:
router.get('/check', (req, res) => {
if (req.query.search) {
var input = req.query.search;
// Put this logic away in a `checkData` function
checkData(input)
.then(data => {
res.render('index', { data }); // Short version of {data: data}
})
.catch(err => {
console.error(err);
res.render('index', { data: null });
});
} else {
res.render('index', { data: null });
}
});
// Here, we have a `retries` parameter, set to 0 initially
function checkData (input, retries = 0) {
const maxRetries = 3;
// Return a promise (you could also use callbacks)
return new Promise((resolve, reject) => {
// Define a retry method
const retry = () => {
if (retries < maxRetries) {
// Increment the retries count and go for another try
checkData(input, retries + 1).then(resolve).catch(reject);
} else {
reject(`Could not get the data after ${retries} retries.`);
}
};
var url = `http://firstapi.com/json/${input}?fields=query`;
request(url, function (error, response, body) {
if (!error && response.statusCode === 200) {
var data = JSON.parse(body);
if (data.query.match(/((^|\.)((25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?\d))){4}$/)) {
var url = 'https://secondapi.com/' + data.query + '?key=something';
request(url, function (error, response, body) {
if (!error && response.statusCode === 200) {
var Data = JSON.parse(body);
// If it worked, resolve with the data
resolve(Data);
} else {
retry();
}
});
} else {
retry();
}
}
});
});
}

Related

function not running in order

For some reason, in node.js, the code is not running in order. It is running the console.log(data2) before even retrieving the data from function2.
I am assuming it is because node.js runs asynchronously. However, I am not too sure how to fix it.
Thanks for all the help in advance
function function1(app){
app.post('/test', (req, res, next) => {
const url = `url1`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
var data2 = function2(data.id);
console.log(data2); //undefined
res.send(profileData);
}
});
})
}
function function2(id){
const url = `url2/${id}`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
console.log(data); //output correct data
return data;
}
});
}
function function1(app){
app.post('/test', (req, res, next) => {
const url = `url1`;
request(url, async function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
var data2 = await function2(data.id);
console.log(data2); //undefined
res.send(profileData);
}
});
})
}
function function2(id) {
const url = `url2/${id}`;
return new Promise(function (resolve, reject) {
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
resolve(JSON.parse(body));
} else {
reject(error);
}
});
});
}
Because you're calling function2() just before outputting console.log(data2). The latter gets executed immediately, while the former has to make a server request. Pass data2 to function2() instead and output it after you output the result from function2()
function function1(app){
app.post('/test', (req, res, next) => {
const url = `url1`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
var data2 = function2(data.id, data2);
res.send(profileData);
}
});
})
}
function function2(id, data2){
const url = `url2/${id}`;
request(url, function(error, response, body) {
if(!error && response.statusCode == 200) {
var data = JSON.parse(body);
console.log(data); //output correct data
console.log(data2); //undefined
return data;
}
});
}

Different response on NodeJS and Postman [duplicate]

I want to open a page up in node and process the contents in my application. Something like this seems to work well:
var opts = {host: host, path:pathname, port: 80};
http.get(opts, function(res) {
var page = '';
res.on('data', function (chunk) {
page += chunk;
});
res.on('end', function() {
// process page
});
This doesn't work, however, if the page returns an 301/302 redirect. How would I do that in a reusable way in case there are multiple redirects? Is there a wrapper module on top of the http to more easily handle processing http responses from a node application?
If all you want to do is follow redirects but still want to use the built-in HTTP and HTTPS modules, I suggest you use https://github.com/follow-redirects/follow-redirects.
yarn add follow-redirects
npm install follow-redirects
All you need to do is replace:
var http = require('http');
with
var http = require('follow-redirects').http;
... and all your requests will automatically follow redirects.
With TypeScript you can also install the types
npm install #types/follow-redirects
and then use
import { http, https } from 'follow-redirects';
Disclosure: I wrote this module.
Is there a wrapper module on top of the http to more easily handle processing http responses from a node application?
request
Redirection logic in request
Make another request based on response.headers.location:
const request = function(url) {
lib.get(url, (response) => {
var body = [];
if (response.statusCode == 302) {
body = [];
request(response.headers.location);
} else {
response.on("data", /*...*/);
response.on("end", /*...*/);
};
} ).on("error", /*...*/);
};
request(url);
Update:
Now you can follow all redirects with var request = require('request'); using the followAllRedirects param.
request({
followAllRedirects: true,
url: url
}, function (error, response, body) {
if (!error) {
console.log(response);
}
});
Here is my (recursive) approach to download JSON with plain node, no packages required.
import https from "https";
function get(url, resolve, reject) {
https.get(url, (res) => {
// if any other status codes are returned, those needed to be added here
if(res.statusCode === 301 || res.statusCode === 302) {
return get(res.headers.location, resolve, reject)
}
let body = [];
res.on("data", (chunk) => {
body.push(chunk);
});
res.on("end", () => {
try {
// remove JSON.parse(...) for plain data
resolve(JSON.parse(Buffer.concat(body).toString()));
} catch (err) {
reject(err);
}
});
});
}
async function getData(url) {
return new Promise((resolve, reject) => get(url, resolve, reject));
}
// call
getData("some-url-with-redirect").then((r) => console.log(r));
Here is function I use to fetch the url that have redirect:
const http = require('http');
const url = require('url');
function get({path, host}, callback) {
http.get({
path,
host
}, function(response) {
if (response.headers.location) {
var loc = response.headers.location;
if (loc.match(/^http/)) {
loc = new Url(loc);
host = loc.host;
path = loc.path;
} else {
path = loc;
}
get({host, path}, callback);
} else {
callback(response);
}
});
}
it work the same as http.get but follow redirect.
In case of PUT or POST Request. if you receive statusCode 405 or method not allowed. Try this implementation with "request" library, and add mentioned properties.
followAllRedirects: true,
followOriginalHttpMethod: true
const options = {
headers: {
Authorization: TOKEN,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
url: `https://${url}`,
json: true,
body: payload,
followAllRedirects: true,
followOriginalHttpMethod: true
}
console.log('DEBUG: API call', JSON.stringify(options));
request(options, function (error, response, body) {
if (!error) {
console.log(response);
}
});
}
If you have https server, change your url to use https:// protocol.
I got into similar issue with this one. My url has http:// protocol and I want to make a POST request, but the server wants to redirect it to https. What happen is that, turns out to be node http behavior sends the redirect request (next) in GET method which is not the case.
What I did is to change my url to https:// protocol and it works.
Possibly a little bit of a necromancing post here, but...
here's a function that follows up to 10 redirects, and detects infinite redirect loops. also parses result into JSON
Note - uses a callback helper (shown at the end of this post)
( TLDR; full working demo in context here or remixed-version here)
function getJSON(url,cb){
var callback=errBack(cb);
//var callback=errBack(cb,undefined,false);//replace previous line with this to turn off logging
if (typeof url!=='string') {
return callback.error("getJSON:expecting url as string");
}
if (typeof cb!=='function') {
return callback.error("getJSON:expecting cb as function");
}
var redirs = [url],
fetch = function(u){
callback.info("hitting:"+u);
https.get(u, function(res){
var body = [];
callback.info({statusCode:res.statusCode});
if ([301,302].indexOf(res.statusCode)>=0) {
if (redirs.length>10) {
return callback.error("excessive 301/302 redirects detected");
} else {
if (redirs.indexOf(res.headers.location)<0) {
redirs.push(res.headers.location);
return fetch(res.headers.location);
} else {
return callback.error("301/302 redirect loop detected");
}
}
} else {
res.on('data', function(chunk){
body.push(chunk);
callback.info({onData:{chunkSize:chunk.length,chunks:body.length}});
});
res.on('end', function(){
try {
// convert to a single buffer
var json = Buffer.concat(body);
console.info({onEnd:{chunks:body.length,bodyLength:body.length}});
// parse the buffer as json
return callback.result(JSON.parse(json),json);
} catch (err) {
console.error("exception in getJSON.fetch:",err.message||err);
if (json.length>32) {
console.error("json==>|"+json.toString('utf-8').substr(0,32)+"|<=== ... (+"+(json.length-32)+" more bytes of json)");
} else {
console.error("json==>|"+json.toString('utf-8')+"|<=== json");
}
return callback.error(err,undefined,json);
}
});
}
});
};
fetch(url);
}
Note - uses a callback helper (shown below)
you can paste this into the node console and it should run as is.
( or for full working demo in context see here )
var
fs = require('fs'),
https = require('https');
function errBack (cb,THIS,logger) {
var
self,
EB=function(fn,r,e){
if (logger===false) {
fn.log=fn.info=fn.warn=fn.errlog=function(){};
} else {
fn.log = logger?logger.log : console.log.bind(console);
fn.info = logger?logger.info : console.info.bind(console);
fn.warn = logger?logger.warn : console.warn.bind(console);
fn.errlog = logger?logger.error : console.error.bind(console);
}
fn.result=r;
fn.error=e;
return (self=fn);
};
if (typeof cb==='function') {
return EB(
logger===false // optimization when not logging - don't log errors
? function(err){
if (err) {
cb (err);
return true;
}
return false;
}
: function(err){
if (err) {
self.errlog(err);
cb (err);
return true;
}
return false;
},
function () {
return cb.apply (THIS,Array.prototype.concat.apply([undefined],arguments));
},
function (err) {
return cb.apply (THIS,Array.prototype.concat.apply([typeof err==='string'?new Error(err):err],arguments));
}
);
} else {
return EB(
function(err){
if (err) {
if (typeof err ==='object' && err instanceof Error) {
throw err;
} else {
throw new Error(err);
}
return true;//redundant due to throw, but anyway.
}
return false;
},
logger===false
? self.log //optimization :resolves to noop when logger==false
: function () {
self.info("ignoring returned arguments:",Array.prototype.concat.apply([],arguments));
},
function (err) {
throw typeof err==='string'?new Error(err):err;
}
);
}
}
function getJSON(url,cb){
var callback=errBack(cb);
if (typeof url!=='string') {
return callback.error("getJSON:expecting url as string");
}
if (typeof cb!=='function') {
return callback.error("getJSON:expecting cb as function");
}
var redirs = [url],
fetch = function(u){
callback.info("hitting:"+u);
https.get(u, function(res){
var body = [];
callback.info({statusCode:res.statusCode});
if ([301,302].indexOf(res.statusCode)>=0) {
if (redirs.length>10) {
return callback.error("excessive 302 redirects detected");
} else {
if (redirs.indexOf(res.headers.location)<0) {
redirs.push(res.headers.location);
return fetch(res.headers.location);
} else {
return callback.error("302 redirect loop detected");
}
}
} else {
res.on('data', function(chunk){
body.push(chunk);
console.info({onData:{chunkSize:chunk.length,chunks:body.length}});
});
res.on('end', function(){
try {
// convert to a single buffer
var json = Buffer.concat(body);
callback.info({onEnd:{chunks:body.length,bodyLength:body.length}});
// parse the buffer as json
return callback.result(JSON.parse(json),json);
} catch (err) {
// read with "bypass refetch" option
console.error("exception in getJSON.fetch:",err.message||err);
if (json.length>32) {
console.error("json==>|"+json.toString('utf-8').substr(0,32)+"|<=== ... (+"+(json.length-32)+" more bytes of json)");
} else {
console.error("json==>|"+json.toString('utf-8')+"|<=== json");
}
return callback.error(err,undefined,json);
}
});
}
});
};
fetch(url);
}
var TLDs,TLDs_fallback = "com.org.tech.net.biz.info.code.ac.ad.ae.af.ag.ai.al.am.ao.aq.ar.as.at.au.aw.ax.az.ba.bb.bd.be.bf.bg.bh.bi.bj.bm.bn.bo.br.bs.bt.bv.bw.by.bz.ca.cc.cd.cf.cg.ch.ci.ck.cl.cm.cn.co.cr.cu.cv.cw.cx.cy.cz.de.dj.dk.dm.do.dz.ec.ee.eg.er.es.et.eu.fi.fj.fk.fm.fo.fr.ga.gb.gd.ge.gf.gg.gh.gi.gl.gm.gn.gp.gq.gr.gs.gt.gu.gw.gy.hk.hm.hn.hr.ht.hu.id.ie.il.im.in.io.iq.ir.is.it.je.jm.jo.jp.ke.kg.kh.ki.km.kn.kp.kr.kw.ky.kz.la.lb.lc.li.lk.lr.ls.lt.lu.lv.ly.ma.mc.md.me.mg.mh.mk.ml.mm.mn.mo.mp.mq.mr.ms.mt.mu.mv.mw.mx.my.mz.na.nc.ne.nf.ng.ni.nl.no.np.nr.nu.nz.om.pa.pe.pf.pg.ph.pk.pl.pm.pn.pr.ps.pt.pw.py.qa.re.ro.rs.ru.rw.sa.sb.sc.sd.se.sg.sh.si.sj.sk.sl.sm.sn.so.sr.st.su.sv.sx.sy.sz.tc.td.tf.tg.th.tj.tk.tl.tm.tn.to.tr.tt.tv.tw.tz.ua.ug.uk.us.uy.uz.va.vc.ve.vg.vi.vn.vu.wf.ws.ye.yt.za.zm.zw".split(".");
var TLD_url = "https://gitcdn.xyz/repo/umpirsky/tld-list/master/data/en/tld.json";
var TLD_cache = "./tld.json";
var TLD_refresh_msec = 15 * 24 * 60 * 60 * 1000;
var TLD_last_msec;
var TLD_default_filter=function(dom){return dom.substr(0,3)!="xn-"};
function getTLDs(cb,filter_func){
if (typeof cb!=='function') return TLDs;
var
read,fetch,
CB_WRAP=function(tlds){
return cb(
filter_func===false
? cb(tlds)
: tlds.filter(
typeof filter_func==='function'
? filter_func
: TLD_default_filter)
);
},
check_mtime = function(mtime) {
if (Date.now()-mtime > TLD_refresh_msec) {
return fetch();
}
if (TLDs) return CB_WRAP (TLDs);
return read();
};
fetch = function(){
getJSON(TLD_url,function(err,data){
if (err) {
console.log("exception in getTLDs.fetch:",err.message||err);
return read(true);
} else {
TLDs=Object.keys(data);
fs.writeFile(TLD_cache,JSON.stringify(TLDs),function(err){
if (err) {
// ignore save error, we have the data
CB_WRAP(TLDs);
} else {
// get mmtime for the file we just made
fs.stat(TLD_cache,function(err,stats){
if (!err && stats) {
TLD_last_msec = stats.mtimeMs;
}
CB_WRAP(TLDs);
});
}
});
}
});
};
read=function(bypassFetch) {
fs.readFile(TLD_cache,'utf-8',function(err,json){
try {
if (err) {
if (bypassFetch) {
// after a http errror, we fallback to hardcoded basic list of tlds
// if the disk file is not readable
console.log("exception in getTLDs.read.bypassFetch:",err.messsage||err);
throw err;
}
// if the disk read failed, get the data from the CDN server instead
return fetch();
}
TLDs=JSON.parse(json);
if (bypassFetch) {
// we need to update stats here as fetch called us directly
// instead of being called by check_mtime
return fs.stat(TLD_cache,function(err,stats){
if (err) return fetch();
TLD_last_msec =stats.mtimeMs;
return CB_WRAP(TLDs);
});
}
} catch (e){
// after JSON error, if we aren't in an http fail situation, refetch from cdn server
if (!bypassFetch) {
return fetch();
}
// after a http,disk,or json parse error, we fallback to hardcoded basic list of tlds
console.log("exception in getTLDs.read:",err.messsage||err);
TLDs=TLDs_fallback;
}
return CB_WRAP(TLDs);
});
};
if (TLD_last_msec) {
return check_mtime(TLD_last_msec);
} else {
fs.stat(TLD_cache,function(err,stats){
if (err) return fetch();
TLD_last_msec =stats.mtimeMs;
return check_mtime(TLD_last_msec);
});
}
}
getTLDs(console.log.bind(console));

Store mongoose field values into a var and interate through

Been making great waves getting deeper into node.js and mongo but I've hit a bit of a wall.
I've got my data being pushing from a form into a collection with mongoose and I can see it being pulled into a JS file and calling the document with console.log below.
var fields = { 'cheap': 1, 'number': 1 };
var query = userModel.find({}).select(fields);
query.exec(function (err, docs) {
if (err) return handleError(err);
console.log(docs + 'first');
request(url, function(error, response, html) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(html);
//var $el = $("a:contains('Xbox')");
var $el = $('a:contains(' + docs + ')');
console.log(docs + 'second')
if ($el.length) {
client.messages.create({
to: "+ '+ cheap.number +'",
from: "+61418739508",
body: $el.text()
}, function(err, message) {
if(err){
console.log(err);
} else {
console.log(message.sid);
}
});
console.log($el.text());
} else {
console.log('hey');
}
}
});
});
Output:
[ { _id: 561650245b3d0d57ad7f3c72,
cheap: 'menus',
number: '0000000000' } ]
However, now I would like to take the values of the 'cheap' and 'number' fields and store them as a var that I can iterate through on the below function.
Can anyone point me in the right direction for what I need to work on? It very much seems like an elusive missing piece of a puzzle.
Found what I was looking for. Needed a for.. in construct to iterate through the properties of the object. From there I had to call the object and property type and it works.
Magic that fixed it:
var docs;
for (var key in docs) {
var value = docs[key];
console.log(key + ", " + value);
}
Full code:
var query = userModel.find({});
query.exec(function (err, docs) {
if (err) return handleError(err);
//console.log(docs);
var docs;
for (var key in docs) {
var value = docs[key];
console.log(key + ", " + value);
}
request(url, function(error, response, html) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(html);
//var $el = $("a:contains('Xbox')");
var $el = $('a:contains(' + value.cheap + ')');
//console.log($el);
if ($el.length) {
client.messages.create({
to: value.number,
from: "+61418739508",
body: $el.text()
}, function(err, message) {
if(err){
console.log(err);
} else {
console.log(message.sid);
}
});
console.log($el.text());
} else {
console.log('hey');
}
}
});
});
I think the mongoose is async, you should move the request function to exec something like this
` query.exec(function (err, cheap, number) {
if (err) return handleError(err);
console.log(cheap);
request(url, function(error, response, html) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(html);
async.each(cheap, function(iterateCheap, callback){
var $el = $("a:contains(" + cheap + ")");
}, function(err){
if(err) {
console.log(err);
} else {
console.log('We successfully iterate on all cheap')
}
})
......`
UPDATE1:
Or you should use async.js module and waterfall method for this situation

Problems with multiple Node.js callbacks

I'm trying to solve a problem i've been having with a nodejs cronjob of mine. So basically, This request grabs my tracks from soundcloud, I loop through the results and put the data in a mongodb collection. This all works great, but now i'm adding another section to the site, so I need to grab some additional info from another collection.
I have a tracks collection, and an inventory collection. The track id is in both collections to relate the additional track data to the newly pulled tracks. So my question is how can I get this additional track data in? Below i have tried to loop through it and inject the data using mongoose's query.find() but the loops do not work together. The callback of the inventory query will run all in one for loop it seems... I'm not exactly sure whats going on there.
I'm pretty sure you can also inject a document from another collection by referencing it in the schema... but i'm unsure of how to get this working. This would obviously be a better solution as it won't require more code like this.
if anybody has any suggestions for me that would be great!
request({
url: url,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
var o = 1;
for(i=0; i < body.tracks.length; i++){
var last = (i + 1);
var track = body.tracks[i];
if( track.sharing == 'public'){
var invData;
var obj;
db.model('inventory').find({id:track.id}).exec(function(err,item){
//console.log(item[0]);
invData = item[0];
});
console.log(invData, obj);
obj = new TracksModel({
id: track.id,
sharing:track.sharing,
uri:track.uri,
description:track.description,
created_at:track.created_at,
duration:track.duration,
title:track.title,
description:track.description,
order: o,
inventory_data: invData
});
o++;
obj.save(function (err) {
if (!err) {
console.log('Track inserted successfully');
} else {
throw err;
}
});
if(last == body.length){
setTimeout(function(){
console.log("Automatically closing database connection after 5 seconds");
db.close();
}, 5000);
}
}
}
} else {
console.log('An error has occurred: ', error);
}
});
The way you are treating the query callback is wrong. You are assuming that the code starting from "console.log(invData, obj);" will be executed immediately after the db.model.find. That not the correct notion of Callback. How must put that code inside the exec callback function. You may have to use a closure.
Something like:
if (!error && response.statusCode === 200) {
var o = 1;
for(i=0; i < body.tracks.length; i++){
var last = (i + 1);
var track = body.tracks[i];
if( track.sharing == 'public'){
(function(track,last,o){
var invData;
var obj;
db.model('inventory').find({id:track.id}).exec(function(err,item){
//console.log(item[0]);
invData = item[0];
console.log(invData, obj);
obj = new TracksModel({
id: track.id,
sharing:track.sharing,
uri:track.uri,
description:track.description,
created_at:track.created_at,
duration:track.duration,
title:track.title,
description:track.description,
order: o,
inventory_data: invData
});
obj.save(function (err) {
if (!err) {
console.log('Track inserted successfully');
} else {
throw err;
}
});
if(last == body.length){
setTimeout(function(){
console.log("Automatically closing database connection after 5 seconds");
db.close();
}, 5000);
}
});
}(track,last,o);
o++;
}
}
}
Try this out:
var utils = require('restberry-utils');
var Inventory = mongoose.model('Inventory');
var Track = mongoose.model('Track');
request({
url: url,
json: true
}, function (error, response, body) {
if (error || response.statusCode !== 200) {
console.log('An error has occurred: ', error);
return;
}
utils.forEachAndDone(body.track, function(track, iter) {
if (track.sharing !== 'public') {
iter();
return;
}
Inventory.findOne({ id: track.id }, function(err, item) {
new Track({
id: track.id,
sharing: track.sharing,
uri: track.uri,
description: track.description,
created_at: track.created_at,
duration: track.duration,
title: track.title,
description: track.description,
order: o,
inventory_data: item,
}).save(function(err) {
if (err) {
throw err;
} else {
console.log('Track inserted successfully');
iter();
}
})
});
}, function() {
console.log('Done!');
setTimeout(function() {
console.log("Automatically closing database connection after 5 seconds");
db.close();
}, 5000);
})
});

NodeJS: creating a hash and return the value of a function

I have a list of tags that I need to extract. the list is called list.
I'm trying to find all 'og:*' meta that correspond to the list and are available in a fetched html. Then I need to return a hash to the user in JSON that contains these meta tags. But the process method return undefined rather than the hash.
var http = require('http');
var url = require('url');
var request = require('request');
var jsdom = require("jsdom");
var fs = require('fs');
var cssom = require('cssom');
var list = ['title', 'description']; //here the og-tags I need to extract
var meta = {};
function process(url) {
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
jsdom.env({
html: body,
scripts: [
'http://code.jquery.com/jquery-1.5.min.js'
],
done: function(errors, window) {
var $ = window.$;
$('meta[property^="og:"]').each(function() {
for (var element in list) {
if ($(this).attr('property') == 'og:' + list[element]) {
meta[list[element]] = $(this).attr('content');
// this works well, if I do console.log(meta), I get the hash correctly filled.
}
}
});
}
});
}
});
return meta; // this is where the probleme is. This return undefined.
}
http.createServer(function (request, response) {
request.setEncoding('utf8');
response.writeHead(200, {'Content-Type': 'text/plain'});
process(url.parse(request.url, true).query['content'], function(result) {
console.log(result); // prints no result
});
response.end();
}).listen(8124);
console.log('Server running at http://0.0.0.0:8124');
Because request is asynchronous, you need to make process asynchronous as well. That means having process accept a callback parameter that it will call once meta is available. As it is now, process is returning meta before the request callback populates it.
function process(url, callback) {
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
jsdom.env({
html: body,
scripts: [
'http://code.jquery.com/jquery-1.5.min.js'
],
done: function(errors, window) {
var $ = window.$;
$('meta[property^="og:"]').each(function() {
for (var element in list) {
if ($(this).attr('property') == 'og:' + list[element]) {
meta[list[element]] = $(this).attr('content');
callback(null, meta);
}
}
});
}
});
} else {
callback(error);
}
});
}
http.createServer(function (request, response) {
request.setEncoding('utf8');
response.writeHead(200, {'Content-Type': 'text/plain'});
process(url.parse(request.url, true).query['content'], function(error, result) {
console.log(result); // prints no result
});
response.end();
}).listen(8124);

Categories