var express = require('express');
var pg = require('pg');
var app = express();
var connectionString = "postgres://...";
app.get('/', function (req, res, next) {
pg.connect(connectionString, function (err, client, done) {
if (err) {
console.log("not able to get connection " + err);
res.status(400).send(err);
}
client.query('SELECT * FROM employee WHERE empid=$1', [1], function (err, result) {
done(); // closing the connection;
if (err) {
console.log(err);
res.status(400).send(err);
}
res.status(200).send(result.rows);
});
});
});
app.listen(3000, function () {
console.log('Server is running.. on Port 3000');
});
This is my nodejs file and the connectionString is database information that connected heroku and postgreSQL.
But when I run this one, I only get
client.query('SELECT * FROM employee WHERE empid=$1', [1], function (err, result) {
^
TypeError: Cannot read property 'query' of null
How can I solve it?
In your error handler here:
if (err) {
console.log("not able to get connection " + err);
res.status(400).send(err);
}
client.query(...)
You need to add a return so that after you send the error status, the code does not continue to try to execute client.query() because client does not have a valid value in it if there was an error. So, change to this:
if (err) {
console.log("not able to get connection " + err);
res.status(400).send(err);
return;
}
client.query(...)
Though it has less of a consequence, the same is true here:
if (err) {
console.log(err);
res.status(400).send(err);
}
res.status(200).send(result.rows);
Where you need to add a return:
if (err) {
console.log(err);
res.status(400).send(err);
return;
}
res.status(200).send(result.rows);
The overall issue in these two cases is that while res.status(...).send(...) sends the response back to the client, it does not stop your code from continuing to execute after that so you still need proper flow control with if/else or an appropriate return to control the flow of execution of the code so after an error it doesn't immediately go execute other parts of the code that you don't want it to.
Related
I am using pg and node.js. When a user logs in using the auth0 widget I am passing the email it returns and checking my database to see if the user exist. If the user does not exist I am inserting them into the database. I have managed to get this working with a hack job of a function but I would appreciate some help ironing it out.
Problems I am facing.
When checking the database for the email it is not checking it for the whole email address.
var emailCheck = "SELECT id from public.user WHERE email=" + req.body.email;
req.body.email; is actually myemail#example.com
Returns this error,
column "myemail" does not exist
Even though
myemail#example.com
does exist.
regardless of the error it throws it moves on to insert the email address. If it does not exist it inserts it. Since there is a Unique Key on the email it throws an error
duplicate key value violates unique constraint "uk_user_email"
So to fix this my question is why is it not checking for after the # sign? And what logic should I follow to change this function to run the first query and only run the second if the first query does not find the email address in question?
checkRegister: function(req, res) {
pool.connect(function(err, client, done) {
if (err) {
return console.error('error fetching client from pool', err);
} connection
var emailCheck = "SELECT id from public.user WHERE email=" + req.body.email;
var emailInsert = "insert into public.user (user_auth_level,email,account_locked,contract) " +
"values ('1','" + req.body.email + "','false','false')"
client.query(emailCheck, function(err, result) {
if (err) {
return console.error(err.message);
}
});
client.query(emailInsert, function(err, result) {
if (err) {
return console.error(err.message);
}
});
done();
});
pool.on('error', function(err, client) {
console.error('idle client error', err.message, err.stack)
});
}
You need to wrap your value with ' to make it string. Without string wrap, it will be come compare between column. It should be:
var yourQuery = "SELECT id from public.user WHERE email=" + req.body.email; // SELECT id from public.user WHERE email=myemail#example.com
var correntQuery = "SELECT id from public.user WHERE email='" + req.body.email + "'"; // SELECT id from public.user WHERE email='myemail#example.com'
Nodejs is synchronous, your need to use callback or promise to chain your code like below:
checkRegister: function (req, res) {
pool.connect(function (err, client, done) {
if (err) {
console.error(err);
// should return response error like
return res.status(500).send();
}
var emailCheck = "SELECT id from public.user WHERE email=$1";
client.query(emailCheck, [req.body.email], function (err, result) {
if (err) {
console.error(err);
res.status(500).send();
return done(); // always close connection
}
if (result.rowCount > 0) {
let user = result.rows[0]
// return your user
return done(); // always close connection
} else {
var emailInsert = "insert into public.user (user_auth_level, email, account_locked, contract) " +
"values ('1', $1,'false','false') RETURNING *"
client.query(emailInsert, [req.body.email], function (err, result) {
if (err) {
console.error(err);
res.status(500).send();
return done(); // always close connection
} else {
if (result.rowCount > 0) {
let user = result.rows[0]
// return your user
return done(); // always close connection
}
}
});
}
})
})
pool.on('error', function (err, client) {
console.error('idle client error', err.message, err.stack)
});
}
For #1, the issue is that you aren't quoting your input value. Since (I assume) you probably don't want to worry about quoting / escaping / etc your own values, I would look into using parameterized queries. This will help protect you against sql injection (and your current code is very exposed to that).
For #2, it doesn't actually "throw" that error. That method is asynchronous, and provides the error to the callback. If you want to run the queries "in order", you'll need to do something like this:
client.query(emailCheck, function(err, result) {
if (err) {
// should probably do `return done(err);` here
return console.error(err.message);
}
client.query(emailInsert, function(err, result) {
if (err) {
// same thing - probably need done(err) in here
return console.error(err.message);
}
return done();
});
});
Note how the calls are embedded "inside" of each other (inside of the callbacks, specifically).
I am pooling connections to my Postgres DB with pg-pool. I am having trouble, however, sending the results of my queries to the frontend. I assumed that I could use res.send as usual but it is not recognized (I also tried return). Here is my function:
exports.featList = function (req, res) {
pool.connect(function(err, client, done) {
if (err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT * FROM book WHERE featured=true', function (err,res) {
var json = JSON.stringify(res.rows);
return json;
client.release();
});
});
It seems that is not returning the results because in the callback of the client.query you are redeclaring the res variable so you can't access the response object. If you rename this variable from res to results it will be able to return the results to the client:
exports.featList = function (req, res) {
pool.connect(function (err, client, done) {
if (err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT * FROM book WHERE featured=true', function (err, results) {
var json = JSON.stringify(res.rows);
res.json(json);
client.release();
});
});
}
I was wondering , what is the best practice to keep the code DRY when developing node.js api with database calls.
I seems like I'm having alot of repeated code.
For example, look at this:
app.get('/api/users_count', function (req,res) {
pool.connect(function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT count(*) FROM users;', function(err, result) {
done();
if(err) {
return console.error('error running query', err);
}
res.json({"users count": result.rows[0].count});
});
});
});
and this:
app.get('/api/users/:id', function (req,res) {
pool.connect(function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT name FROM users WHERE id=$1;',req.param.id, function(err, result) {
done();
if(err) {
return console.error('error running query', err);
}
res.json({"user name": result.rows[0].name});
});
});
});
How can I avoid the repeating of error handing , connect call, and just focus on route and query.
Thanks!
Take a look at sample below, should help
//Create fn that connects, pulls data, and passes it to callback
function customPool(query, values, callback) {
pool.connect(function(err, client, done) {
if(err)
return callback(err);
client.query(query, values, function(q_err, result) {
done();
if(q_err)
return callback(q_err);
callback(null, result.rows);
});
}
}
//Reuse it
app.get('/api/users_count', function (req,res) {
var query = 'SELECT count(*) FROM users;';
customPool(query, undefined, function(err, rows) {
if(err)
return console.error('error fetching client from pool', err);
res.json({"users count": rows[0].count});
});
});
app.get('/api/users/:id', function (req,res) {
var query = 'SELECT name FROM users WHERE id=$1;';
customPool(query, req.params.id, function(err, rows) { //<-- notice, req.params.id not req.param.id
if(err)
return console.error('error fetching client from pool', err);
res.json({"users name": rows[0].name});
});
});
For starters, use pg-promise for database communications, to avoid connecting manually. Then your code will be way simpler, as shown below.
code 1:
app.get('/api/users_count', function (req, res) {
db.one('SELECT count(*) FROM users')
.then(data=> {
res.json({"users count": +data.count});
})
.catch(error=> {
// should provide a response here also ;)
console.error(error);
});
});
code 2:
app.get('/api/users/:id', function (req, res) {
db.one('SELECT name FROM users WHERE id=$1', +req.param.id)
.then(user=> {
res.json({"user name": user.name});
})
.catch(error=> {
// should provide a response here also ;)
console.error(error);
});
});
Then you can simplify it further, by implementing a generic request->response logic, depending on your application's requirements.
I am testing a nodeJS server, built on the express framework.
When a request is sent to the server, the server should send back some data, in the form of an array. Instead, it is sending back ''.
The test that I am trying to pass is as follows:
it('should send postgres data to the server', function(done) {
request(app)
.post('/chart')
.send({min:"1",max:"100",arrayLength:"12"})
.expect(200, sqlData)
.end(function(err, res){
if(err) {
done(err);
} else {
done();
}
});
});
Note that sqlData is equal to what the sent response should be.
When the router receives a POST request it does the following:
router.post('/', function(req, res) {
res.send(randomSqlTableSelector(req.body.min,req.body.max,req.body.arrayLength));
});
I have checked that req.body.min, max and arrayLength are all the numbers that I would expect them to be.
Thus, the problem is likely in my function randomSqlTableSelector, which, for whatever reason, when called inside of the router, simple returns the empty quotes ''
The function is as follows:
function randomSqlTableSelector(min,max,arrayLength) {
var filledArray = [];
pg.connect(conString, function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT cell1 FROM random AS retrievedNumber;', function(err, result) {
var psqlData = result.rows;
for (i in psqlData) {
filledArray.push(psqlData[i]["cell1"])
}
return filledArray
});
});
}
You cannot treat functions that perform asynchronous, non-blocking tasks as synchronous and blocking. Try passing in a callback instead:
function randomSqlTableSelector(min, max, arrayLength, cb) {
pg.connect(conString, function(err, client, done) {
if (err)
return cb(err);
client.query('SELECT cell1 FROM random AS retrievedNumber;', function(err, result) {
if (err)
return cb(err);
var psqlData = result.rows,
filledArray = [],
i;
for (i in psqlData)
filledArray.push(psqlData[i]["cell1"])
cb(null, filledArray);
});
});
}
Then use it in your route like:
router.post('/', function(req, res) {
var min = req.body.min,
max = req.body.max,
len = req.body.arrayLength;
randomSqlTableSelector(min, max, len, function(err, array) {
if (err) {
console.log(err);
return res.send(500);
}
res.send(array);
});
});
I'm using express and mongoose. I have a weird issue when I'm using mocha test to run this endpoint.
exports.broadcastMessages = function(req, res, next) {
User.find({}, function(err, users) {
if(err) return next(err);
var push = function(user, callback) {
user.messages.push(req.body.message);
user.save(function(err) {
callback(err);
});
};
var fin = function(err) {
if (err) {
return next(err);
}
console.log('aaaaaaaaaa');
return res.send('ok');
};
async.each(users, push, fin);
});
};
Then I got a timeout error. There is only one user. So it's not a time issue. And I'm sure res.send('ok') was called. But when I removed user.save(). It worked...
exports.broadcastMessages = function(req, res, next) {
User.find({}, function(err, users) {
if(err) return next(err);
var push = function(user, callback) {
user.messages.push(req.body.message);
callback(err);
};
var fin = function(err) {
if (err) {
return next(err);
}
console.log('aaaaaaaaaa');
return res.send('ok');
};
async.each(users, push, fin);
});
};
I don't know why. Why added one more user.save() it doesn't work? res.send is called but no response.
The version of express is 3.4.7. Mongoose is 3.8.2.
When you say "I got a timeout error" do you mean mocha failed your test for taking too long? If so that is probably a problem in your mocha test itself not calling done() correctly. The above code looks OK to me and I think it should work. Some misc points:
Whenever you have this pattern:
user.save(function(err) {
callback(err);
});
You don't need that extra wrapper function that does nothing but call the callback. Just do:
user.save(callback);
Also, looping through the users and saving each one is much less efficient than just having mongodb do them all for you in a single command:
User.update({}, {$push: {messages: req.body.message}}, function (error) {...});