NodeJS passing an extra param to a callback - javascript

I'm a begginer in Node.JS and as a first tryout i'm implementing a small url shortening service that will get a request with an id parameter and redirect to the actual url after searching a cassandra database.
Below you can find my implementation.
var reqResponse;
app.get('/r/:id', function(req, res) {
reqResponse = res;
conn.connect(function(err, keyspace) {
if(err){
throw(err);
}
conn.cql(cqlSelectStatement, [req.params.id], { gzip:true }, redirectCallback);
});
});
function redirectCallback (err, results) {
if (err != null) {
//log
} else {
if (results.length > 0) {
results.every(function(row){
reqResponse.writeHead(config.redirectStatus, {
'Location': row[0].value
});
reqResponse.end();
return false;
});
} else {
reqResponse.send("There was a problem!");
return false;
}
}
conn.close();
return true;
}
It works fine, it does the job, but i'm having some doubts about that reqResponse "global" variable. I don't like it there.
Is there a way I could send "res" as a parameter to the redirectCallback function?
Thank you!

Yes there is: Create an anonymous function and use that to pass the parameter:
app.get('/r/:id', function(req, res) {
conn.connect(function(err, keyspace) {
if(err){
throw(err);
}
conn.cql(cqlSelectStatement, [req.params.id], { gzip:true }, function (err, results) { redirectCallback(err, res, results); } );
});
});
And your callback becomes:
function redirectCallback (err, res, results) {

Related

How to send the a return object in function

I´m trying to create a function that make a request to a website and, as the return of the function, I want to deliver the object "BODY" created by the request. But everytime I have "Object undefined" return.
What I need to change in order to deliver this result ?
Here are the code:
// ---- Funções --------------------------------------------------------------------------------//
function consultaCep(cep){
request(`https://viacep.com.br/ws/${cep}/json/`, {json: true}, (err, res2, body) => {
if(err) return console.log(`Erro na consulta: ${err}`)
return body;
});
}
// Rotas ------------------------------------------------------------------------------------//
app.get('/', (req,res)=> {
x = consultaCep('13085485');
console.log(x);
res.end(x);
Thanks a lot.
There are many ways to achieve this. You can use a callback.
You can pass a callback to the method that invokes the web request, and invoke that callback from within that method:
var consultaCep = function(callback){
request('https://viacep.com.br/ws/${cep}/json/', function (error, response, body) {
if (!error && response.statusCode == 200) {
status = "succeeded";
callback(null, {status : status});
} else {
callback(error);
}
})
}
app.get('/', function(req, res){
consultaCep(function(err, result){
if(err){
res.send(500, { error: 'Something went wrong' });
} else {
res.send(result);
}
});
});

Node.js 'headers already sent' when page is refreshed

I keep getting this error (after a certain amount of time) when i refresh the my 'members area' after login. I use response.redirect to redirect to the area (success) or back to sign in form (error). How can i fix this?
app.get('/sellers/login', function(request, response) {
if(request.session.sellerId){
response.redirect( '/sellers/area?logged_in=true');
}
else{
response.render('pages/sellers-login');
}
});
app.post('/authenticate', function(request, response) {
if(request.session.sellerId){
response.redirect('/area?logged_in=true');
}
else{
db.authenticate(request.body.loginid, function(err, results) {
if(err){
response.redirect('/sellers/login?err=1&logged_in=false&type=db');
}
else{
if(results.length >=1){
var hash = results[0]['hash'];
var seller_id = results[0]['id'];
bcrypt.compare(request.body.password, hash, function(err, res) {
if(res){
request.session.sellerId = seller_id;
response.redirect('/sellers/area?logged_in=true');
}
else{
response.redirect('/sellers/login?err=1&logged_in=false&type=pMatch');
}
});
}
else{
response.redirect('/sellers/login?err=1&logged_in=false&type=user');
}
}
});
}
});
app.get('/sellers/area', function(request, response) {
if(request.session.sellerId){
response.render('pages/sellers-area');
}
else{
response.redirect('/sellers/login?not_logged_in=true');
}
});
if(request.session.sellerId){
response.redirect('/area?logged_in=true');
}
db.authenticate(request.body.loginid, function(err, results) {
// ....
});
You send the header when request.session.sellerId evaluates to true by calling the response.redirect, but you continue with the the db.authenticate afterwards.
Inside of that callback you will do another redirect, even when your redirect for that response has already taken place.
Inside of the db.authenticate you have the same problem with the if(err)
EDIT
you need to use an else block (or a return) for both the if (request.session.sellerId) and the if (err) {
if (request.session.sellerId) {
response.redirect('/area?logged_in=true');
} else {
db.authenticate(request.body.loginid, function(err, results) {
if (err) {
response.redirect('/sellers/login?err=1&logged_in=false&type=db');
} else if (results.length >= 1) {
var hash = results[0]['hash'];
var seller_id = results[0]['id'];
bcrypt.compare(request.body.password, hash, function(err, res) {
if (res) {
request.session.sellerId = seller_id;
response.redirect('/sellers/area?logged_in=true');
} else {
response.redirect('/sellers/login?err=1&logged_in=false&type=pMatch');
}
});
} else {
response.redirect('/sellers/login?err=1&logged_in=false&type=user');
}
});
}
I think i've found precisely where the error originates from which lies in the db.authenticate
//db.js
exports.authenticate = function(loginid, callback) {
var sql = "select ...";
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
callback(true);
return;
}
connection.query(sql, [loginid], function(err, results) {
connection.release();
if(err) {
console.log(err);
callback(true);
return;
}
callback(false, results);
});
connection.on('error', function(err) {
console.log(err);
connection.release();
callback(true);
return;
});
});
};
The connection.on('error',... gets called, so the callback(true) activates causing this error.

Scope issue calling a callback function inside a loop in node.js

With the help of glortho in this thread i built this code:
for(var i=0;i<datos.length;i++){
bittrex.getticker(datos[i].Currency, function(err, data){
if (err){
console.log('ERROR:', err);
return 'ERROR:'+ err;
} else {
if (data.message!='INVALID_MARKET') {
this.LasValueBTC=data.result.Last;
} else {
this.LasValueBTC='';
}
}
}.bind(datos[i]));
}
The problem is that outside the callback function the datos array is not updated...As it is written at the moment if i console.log(this) inside the function works great and this.LastValueBTC exists in my json, but outside the function if i console.log(datos) after the loop, the LastValueBTC does not exist..and i need to do a res.send(datos) after the loop..
What you need to do is wait for all the callbacks to complete and then call res.send.
var count = datos.length;
for(var i=0;i<datos.length;i++){
bittrex.getticker(datos[i].Currency, function(err, data){
if (err){
console.log('ERROR:', err);
return 'ERROR:'+ err;
} else {
if (data.message!='INVALID_MARKET') {
this.LasValueBTC=data.result.Last;
} else {
this.LasValueBTC='';
}
count--;
if (count === 0) {
res.send(datos);
}
}
}.bind(datos[i]));
}
Or using async
async.each(datos, function(dato, next) {
bittrex.getticker(dato.Currency, function(err, data) {
if (err){
console.log('ERROR:', err);
next(err);
} else {
if (data.message!='INVALID_MARKET') {
dato.LasValueBTC = data.result.Last;
} else {
dato.LasValueBTC='';
}
next();
}
});
}, function(err) {
res.send(datos);
});
Go through this article http://www.richardrodger.com/2011/04/21/node-js-how-to-write-a-for-loop-with-callbacks/#.VTXnFa2eDGc
It gives a good conceptual overview on what happens if you put functions inside for loop

Connection.query to execute

Pretty sure this is a quite noobish node.js/callback question but I can't seem to find the proper code to make it run.
This is how I invoke my node-mysql code:
var utils = require('../../config/database/utils');
exports.getResults = function(callback) {
var query = "SELECT * FROM my_table";
utils.exec(query, null, function(err, results){
if(err){
console.log(err);
callback(true);
return;
}
console.log(results);
callback(false, results);
});
};
Next is the utils file where I can't get the code work.
var pool = require('./connection');
module.exports = {
getDBConnection: function() {
pool.getConnection(function(err, connection){
if(err){
console.log(err);
return;
}
return connection;
});
},
endDBConnection: function(connection) {
connection.end(function (err) {
if(err) {
console.log(err);
callback(true);
return;
}
});
},
exec: function(query, data, callback) {
console.log(query);
this.getDBConnection(function(err, connection){
if(err){
console.log('error');
}
console.log(connection);
connection.query(query, data, function(err, results) {
if(err) {
callback(err);
}
callback(false, results);
});
this.endDBConnection(connection);
});
}
}
Code is getting OK the the exec part since the console.log(query) logs the query. But after that, the code's not running, console.log(connection); doesn't show a thing, and of course the connection.query is also not running.
I'm not sure why this is happening.
Returning a value inside a callback is meaningless. You need to pass in a callback that gets called with the value you want to return:
getDBConnection: function(callback) {
pool.getConnection(function(err, connection){
if(err){
console.log(err);
return callback(err);
}
callback(null, connection);
});
},
You should also use connection.release() instead of connection.end() since you are using a pool:
endDBConnection: function(connection) {
connection.release();
},
In exec(), you have the wrong this. It should instead be something like:
exec: function(query, data, callback) {
console.log(query);
var self = this;
this.getDBConnection(function(err, connection){
if(err){
console.log('error');
return callback(err);
}
console.log(connection);
connection.query(query, data, function(err, results) {
self.endDBConnection(connection);
if(err) {
return callback(err);
}
callback(null, results);
});
});
}

How to wait for a response from a mongo findOne query in a node/express app before using the response in following control flow

I am new to node, and also JavaScript callbacks.
I am trying to check if an account exists in mongo and then 'save it' if it doesn't and return an error if it does.
I am currently trying to figure this out outside of my express app. This is what i have..
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (doc) {
if(doc) {
console.log('account exists');
} else {
console.log('good to go');
}
console.dir(doc);
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
if(err) throw err;
db.close();
callback();
});
}
with the console.dir(doc); above returning as undefined. How do I wait for the findOne to return before using the callback to console.log or save the account?
The reason you are getting undefined is because when you call your callback your are not passing it the doc. That line should look like callback(doc).
Here is an updated version of your code with a few suggestions:
MongoClient.connect('mongodb://localhost:27017/main', function (err, db) {
if(err) throw err;
var query = { name : "www.website.com"}
findOne(db, query, function (err, doc) {
if(err) {
// something went wrong
console.log(err);
return;
}
if(doc) {
console.log('account exists');
console.dir(doc);
} else {
console.log('good to go');
}
});
});
var findOne = function (db, query, callback) {
db.collection('accounts').findOne(query, function (err, doc) {
db.close();
if(err) {
// don't use throw when in async code
// the convention is to call your callback with the error
// as the first argument (notice that I added an argument
// to the definition of your callback above)
callback(err);
}
else {
// call your callback with no error and the data
callback(null, doc);
}
});
}

Categories

Resources