I’m getting an error when trying to fetch data with the instagram-node package while using request parameters.
Making the call without parameters but hard coded values works without any errors and gives me the right result.
When I use the parameters, as shown below, I get the following error:
{ [Error: Wrong params "lat" & "lng"] retry: [Function] }
This is my code:
//http://localhost:8080/photos/2000/52.3677985/4.8852246
app.get('/photos/:dist/:longitude/:latitude', function(req,res) {
var dist = req.params.dist;
var longitude = req.params.longitude;
var latitude = req.params.latitude;
console.log(dist + " " + longitude + " " + latitude);
ig.media_search(longitude, latitude, {distance: dist},
function (err, medias, remaining, limit) {
if (err) {
console.log(err);
} else {
res.render('pages/index', {grams: medias});
}
});
Logging the parameters gives me the required values, but they don’t seem to be defined when making the ig.media_search() call.
Am I missing something here?
The first thing that I'm seeing is that you're sending in latitude and longitude in backwards. The signature is:
media_search = function(lat, lng, options, cb) {}
Secondly, this is the line that is throwing your error from instagram-node:
if(typeof lat !== 'number' || typeof lng !== 'number') {
return handle_error(new Error('Wrong params "lat" & "lng"'), cb, retry);
}
I'm going to guess that you're sending in string values that have the numbers you want as they were parsed out of the url string. If you try calling it like this, you might see better results:
//http://localhost:8080/photos/2000/52.3677985/4.8852246
app.get('/photos/:dist/:longitude/:latitude', function(req,res) {
// Cast as numbers to send into instagram.
var dist = Number(req.params.dist);
var longitude = Number(req.params.longitude);
var latitude = Number(req.params.latitude);
console.log(dist + " " + longitude + " " + latitude);
ig.media_search(latitude, longitude, {distance: dist},
function (err, medias, remaining, limit) {
if (err) {
console.log(err);
} else {
res.render('pages/index', {grams: medias});
}
});
By the way, I've never used this package before. If you go from the npm page for this package you can find a link to the github repo for it. If you look at their package.json you can find a main value that will lead you to the entry point for the package. In that file (lib/instagram.js) you can Ctrl+F for media_search and find the function in you're calling. Just thought you might want to know how to go through and debug something like this. :)
Related
I am using expressJs to route some POST requests.
From the client side I pass an object of objects and in the server I iterate over each of them with a for loop.
My problem, the variable cantidad in the loop only takes the first value instead of being refreshed into the pool.query, but before the pool.query it takes the right value.
So, the line below is ok.
console.log("cantidad before query: " + cantidad);
But the line below is bad. It has the first value.
console.log("cantidad in query: " + cantidad);
This is part of my code.
for (var key in objects) {
if (objects.hasOwnProperty(key)) {
...
console.log("cantidad before query: " + cantidad);
pool.query(qProducto,idProducto, function (error, results, fields {
if (error) {
...
} else {
console.log("cantidad in query: " + cantidad);
...
This is the full POST in ExpressJs.
app.post("/commanda", function (req, res) {
var idCuenta = req.body.idCuenta;
var idEmpleado = req.body.idEmpleado;
var fechaRegistro = req.body.fechaRegistro;
var cuenta_mesero = "C:" + idCuenta + ":E:" + idEmpleado;
var objects = req.body.objects;
var element = {};
for (var key in objects) {
if (objects.hasOwnProperty(key)) {
var qProducto = "SELECT descripcionProducto FROM PRODUCTO WHERE idProducto = ? ;";
var descProducto = '';
console.log("cantidad in commanda2 : " + objects[key].cantidad );
try {
pool.query(qProducto, objects[key].idProducto, function (error, results, fields) {
if (error) {
console.error(error);
console.error("Failed with query: " + qProducto);
res.status(500).end();
throw error;
} else {
console.log("cantidad in commanda4 : " + objects[key].cantidad );
descProducto = JSON.stringify(results[0].descripcionProducto);
element = {
idProducto:objects[key].idProducto,
cantidad:objects[key].cantidad,
descProducto:descProducto,
cuenta_mesero:cuenta_mesero,
fechaRegistro:fechaRegistro
};
imprimirOrden(element);
}
});
} catch (error) {
callback(error);
}
}
}
printer.printVerticalTab();
res.status(200).end();
});
This is how an object looks like.
{ '0':
{ idProducto: '28',
cantidad: '3',
descProducto: 'Product1',
precioProducto: '3500',
precioTotal: 10500,
'$$hashKey': 'object:345' },
'1':
{ idProducto: '29',
cantidad: '2',
descProducto: 'Product2',
precioProducto: '4500',
precioTotal: 9000,
'$$hashKey': 'object:346' } }
This happens because the function for is synchronous but the function poll.query is asynchronous. What this means is that using the for loop you are essentially queuing some queries. You are not executing them one by one. So the for loop will finish before even one result is returned from the query. If you want to use data from the query for the next iteration you should start using async.js, an npm module that helps you avoid this problems. TL;DR the console log that you think runs in query is actually run before even one query has finished. More information is needed on where you declare the variable cantidad and when you change it to accurately understand the problem.
UPDATE:
What I told you at first was quite wrong because of the fact that I misunderstood the in-detention of the else {}. But what I told you already is actually the problem. It was well obfuscated.The for loop finishes before even one query has finished. They are just queued. So the second console.log will have the key of the last key in the loop. If you need logic that requires knowing in which iteration you are you should implement an async function in order to know in which iteration you actually are. If you don't want to use the async library you can use something like this.
First add this function in the bottom of your js file
https://pastebin.com/4tR0xaTY
You essentially created an async for loop that you can now know in which iteration you are using loop.iteration(). Then replace your post code with the code written below ( To include the async loop ).
https://pastebin.com/YzZU7bqp
I'm trying to make an implementation using nodejs with jsftp libraries.
This is my piece of code:
function sftpOperation(bigstring, res) {
values = bigstring.split("#"),
connProperties = {
desthost: values[0],
destuser: values[1],
destpass: values[2]
},
destpath=values[3],
sourfile=values[4],
client = new jsftp({host:connProperties.desthost,
port:22,
user:connProperties.destuser,
pass:connProperties.destpass,
debugMode: true});
client.auth(connProperties.destuser, connProperties.destpass, function(hadErr){
if (!hadErr){console.log("auth succesfull");}
});
client.put('/home/nagios/out','/home/jboss/outnew', function(hadErr){
if (!hadErr){
res.end("OK");
}
else
res.end("KO : " + err);
});
}
The callback function didn't return nothing... the if statement after callback is completely skipped.
Looking at properties for object "client", I see that Command queue properties contain one object (CommandQueue[1] with value "action jboss", where 'jboss' is the value for connProperties.destuser).
Can someone help to understand what's going wrong with this?
This node/express function is giving me an error:
Can't set headers after they are sent.
it used to work fine, but i have made some changes to the user schema, moving all address items to be under 'address', like this:
firstname,
lastname,
address:{
street,
city,
loc (array of numbers)
...
}
so the new function looks like this:
export function searchMembers(req, res) {
var lat = req.body.lat;
var lon = req.body.lon;
var zoom = req.body.zoom || 14;
var query = User.find();
var distance = 5000;
// when this line is removed, problem is gone:
query = query.where('address.loc').near({center:{type:'Point', coordinates:[lon,lat]}, maxDistance: distance, spherical:true});
query = query.where({'address.city': 'Toronto'});
query = query.sort({'lastname': 1});
query.exec(function(err,users){
if(err) res.send(err);
var final = [];
_.forEach(users, function(x){
var obj = {};
obj.id = x._id;
obj.name=x.firstname + ' ' + x.lastname;
obj.latitude=x.address.loc[1] ;
obj.longitude=x.address.loc[0] ;
final.push(obj);
});
res.status(200).json(final);
});
}
So when i run this, i get the funny error: Can't set headers after they are sent.
pointing to the last line in the function:
res.status(200).json(final);
i tried to eliminate stuff to find the root cause.
when i remove the where line with the 'near' function, the problem is gone.
i have added other filtering, just for testing, everything fine. only this one is causing an issue.
Any idea?
This error means, that you already used method res.json()/render()/send() and you try to do it again.
In your case, this line does not stop method from executing if(err) res.send(err);
You have to write return to stop it.
if(err) {
res.send(err);
return;
}
Which is equivalent to
if(err) {
return res.send(err);
}
Just do not think about it as returning "res.send(err)", it is using res.send(err) and after that using return to stop executing.
The reason why removing line also removes error :
You have some error in that line (like having bad column names), therefore in callback the error is send and then you use res.send(err) and after that you call res.status(200).json(final)
I am creating an insert script that does some business logic.
Basically, I want to check to see if a value in the inserted item exists in a table. But, it seems like if I find a problem Request.Send() doesn't stop execution and get an error.
I think there is an async issue here. I'm not 100% sure how to solve.
Is there a way to stop execution of the script?
if (item.memberType === 'Family' && item.primaryFamilyMember) {
table
.where({
memberNumber: item.primaryFamilyMember,
memberType: 'Family',
primaryFamilyMember: null })
.read({
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
validInsert = false;
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
}
}
});
}
if (validInsert) {
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
table.includeTotalCount().where(function(prefix){
return this.memberNumber.substring(0, 4) === prefix;
}, prefix)
.take(0).read({
success: function (results) {
if (isNaN(results.totalCount)) {
results.totalCount = 0;
}
item.memberNumber = prefix + ('00' + (results.totalCount + 1)).slice(-3);
request.execute();
}
});
}
Yes, validInsert is declared at the top of the insert function.
I assume what's happening is the if(validInsert) runs before the read callback. But if so, i'm not sure why I'm getting "Error: Execute cannot be called after respond has been called." That implies the callback is running first.
Also, the record is being inserted when it shouldn't be even though the 400 error is sent back to the client.
This is an express app right? Should I just call response.end() after the error occurs?
Yes, there are definitely asyn issues in that code. To solve get rid of your validInsert flag and simply move the if (validInsert) section into the success callback (or make it a function called from the success callback). For example:
success: function(results) {
if (results.length == 0) {
request.respond(statusCodes.BAD_REQUEST,
'Invalid Primary Family Member specified.');
console.error('Invalid Primary Family Member specified:' + item.primaryFamilyMember);
} else {
item.memberType = results[0].memberType;
item.memberLevel = results[0].memberLevel;
item.dateOfExpiry = results[0].dateOfExpiry;
var today = new Date();
var prefix = today.getFullYear().toString().substr(2,2) + ('0' + (today.getMonth() + 1)).slice(-2);
...
//respond successfully
}
}
I am toying with Q and promptly and I am trying to ask, in a sequence, the user to input some stuff. For example :
What is your name? Bob
What is your age? 40
Hello Bob (40)!
(yes! it's a simple "Hello world!" program.)
And here is the code I am trying, directly from Q's github project page :
Q.fcall(promptly.prompt, "What is your name? ")
.then(promptly.prompt, "What is your age? ")
.done(function(name, age) {
console.log("Hello " + name + " (" + age + ")");
});
});
But it is not working as expected (maybe I'm reading wrong?). Whatever I try, it seems that promptly.prompt is listening to keystroke in parallel, and the .done function is called right away, resulting into a
/path/to/node_modules/promptly/index.js:80
fn(null, data);
^
TypeError: undefined is not a function
at /path/to/node_modules/promptly/index.js:80:9
...
once I hit Enter. Any idea why this is doing so and how I can accomplish what I'm trying to do?
** Edit **
Basically, what my end goal would be to create a reusable function invoked like so :
promptAll({
'name': "What is your name? ",
'age': "What is your age? "
}).done(function(input) {
console.log(input); // ex: { name: "Bob", age: 40 }
});
** Update **
Here's my working solution, I had to use nfcall as suggested by WiredPraine :
function multiPrompt(args) {
function _next() {
if (keys.length) {
var key = keys.pop();
Q.nfcall(promptly.prompt, args[key]).done(function(value) {
result[key] = value;
_next();
});
} else {
def.resolve(result);
}
};
var def = Q.defer();
var keys = _.keys(args).reverse();
var result = {};
_next();
return def.promise;
};
(Note : I am using Underscore, but the same can be achieved with a standard object iterator.)
Below are two approaches.
First, you'd need to use nfcall so that Q uses the NodeJS conventions for callbacks.
But, as the functions aren't promises, you'll need to handle the chaining and synchronous behavior slightly differently.
In the first example, start1, the code creates an instance of defer and returns it as the promise. When the prompt function returns, it resolves the deferred object instance and passes the value of the function (ideally the prompt). It should also handle errors, etc. in "real" code.
In both examples, I've added a function to grab the result of the the promise resolving. It's not passed as parameters to the last done instance. The function passed to done will execute as soon as the first promise is resolved (after the prompt has returned in this case).
var promptly = require('promptly');
var Q = require('q');
// make a simple deferred/promise out of the prompt function
var prompter = function(text) {
var deferred = Q.defer();
promptly.prompt(text, function(err, value) {
deferred.resolve(value);
});
return deferred.promise;
};
// this option just uses the promise option to prompt for name.
function start1() {
prompter("What is your name?").then(function(name) {
prompter("Your age?").then(function(age) {
console.log("Hello " + name + " (" + age + ")");
});
});
}
// this one uses the nfcall funcitonality to directly call the
// promptly.prompt function (and waits for a callback).
function start2() {
Q.nfcall(promptly.prompt, "What is your name? ")
.then(function(name) {
Q.nfcall(promptly.prompt, "What is your age? ")
.done(function(age) {
console.log("Hello " + name + " (" + age + ")");
});
});
}
//start1();
I feel like the answers here can be added to for anyone seeking alternatives to solving the general problem of getting command line user input from node.
Firstly, I personally feel there is merit to moving towards the ES6 Promises API. Although not natively available yet in Node, there is a great polyfill: https://github.com/jakearchibald/es6-promise.
Secondly, I have come to like an alternative user prompting module: https://github.com/flatiron/prompt
Now assuming there exist methods 'addUserToDb', 'printUser' and 'printError' that in turn return promises, the following example is possible:
var prompt = require('node-prompt');
var Promise = require('es6-promise').Promise;
var promptUser = function(schema) {
return new Promise(resolve, reject) {
prompt.get(schema, function(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
};
};
promptUser(["name", "password"])
.then(addUserToDb)
.then(printUser)
.catch(printError)
I've written many 'scripts' now using this method and have found it very nice to work with and easy to maintain / adapt.