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();
});
});
}
Related
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.
So I have a node app using express router and routes, for example I have a router that handles fetching company objects from the database, within the Company router the get method looks like this:
router.get('/:id', function(req, res, next) {
var id = req.params.id;
models.Company.get(Number(id), function(err, entity) {
if (err) {
console.error("Get error:", err);
}
console.log('Got entity:', entity);
req.data = entity;
next()
});
});
Now if I am in another router, say the Reviews router and I want to get a company I would like to be able to call this route in order to grab that company, instead of having to duplicate code.
How do I do that?
You can either use a named function, if you really want to use the same handler:
function yourHandler(req, res, next) {
var id = req.params.id;
models.Company.get(Number(id), function(err, entity) {
if (err) {
console.error("Get error:", err);
}
console.log('Got entity:', entity);
req.data = entity;
next()
});
}
router.get('/:id', yourHandler);
router2.get('/companies/:id', yourHandler);
Or you can abstract away only the actual database lookup, by making a function that takes a callback:
function getCompany(id, callback) {
models.Company.get(Number(id), function(err, entity) {
if (err) {
console.error("Get error:", err);
callback(err);
} else {
console.log('Got entity:', entity);
callback(null, entity);
}
});
}
or a function that returns a promise:
function getCompany(id) {
return new Promise(function (resolve, reject) {
models.Company.get(Number(id), function(err, entity) {
if (err) {
console.error("Get error:", err);
reject(err);
} else {
console.log('Got entity:', entity);
resolve(entity);
}
});
});
}
The difference is that you use the callback-taking version like this:
getCompany(123, function (err, data) {
if (err) {
// handle error
} else {
// you have data
}
});
and you use the promise-returning version like this:
getCompany(123)
.then(function (data) {
// you have data
})
.catch(function (err) {
// handle error
});
The callback versions are easy to compose using the async module and the promise versions are easy to compose using the bluebird module or some other promise framework. See:
http://caolan.github.io/async/
http://bluebirdjs.com/
It's also worth mentioning that Bluebird is much faster than native ES6 promises, see this answer for details.
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.
module.exports.validateUser = function (req, res) {
User.find({ 'username': req.body.username, 'password': req.body.password }, function (err, result) {
if (result.length) {
var gridfs = req.app.get('gridfs');
var readstream = gridfs.createReadStream({
_id: result[0]._doc.picture
});
req.on('error', function (err) {
res.send(500, err);
});
readstream.on('error', function (err) {
res.send(500, err);
});
// Just sends the file
//readstream.pipe(res);
res.send('This is incedible');
} else {
res.send(false);
}
});
};
Just after the user is validated I am getting the file associated with it. Further I want to send some data along with the fine in response. I've used multer and gridfs-stream. Is this achievable. If not, then does something looks fishy in this approach?
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);
});
});