I'm writing my first (non tutorial) node application and am at a point where I'm writing a function that should take the username and password as parameters and query them against the user table of my database to return either true or false. The database is setup, and the app is connecting to it successfully.
However, I haven't worked with SQL very much, nor node, and I'm unsure how to proceed with this function (and short surrounding script). Here it is:
console.log('validator module initialized');
var login = require("./db_connect");
function validate(username, password){
connection.connect();
console.log('Connection with the officeball MySQL database openned...');
connection.query(' //SQL query ', function(err, rows, fields) {
//code to execute
});
connection.end();
console.log('...Connection with the officeball MySQL database closed.');
if(){ //not exactly sure how this should be set up
return true;
}
else{ //not exactly sure how this should be set up
return false;
}
}
exports.validate = validate;
This is using node-mysql. I'm looking for a basic example of how I might set the query and validation up.
I think you'll want to rethink your app into a more node-like way (i.e. one that recognizes that many/most things happen asynchronously, so you're not usually "returning" from a function like this, but doing a callback from it. Not sure what you plan to get from node-mysql, but I would probably just use the plain mysql module. The following code is still most likely not entirely what you want, but will hopefully get you thinking about it correctly.
Note that the use of 'return' below is not actually returning a result (the callback itself should not return anything, and thus its like returning undefined. The return statements are there so you exit the function, which saves a lot of tedious if/else blocks.
Hope this helps, but I'd suggest looking at various node projects on github to get a better feel for the asynchronous nature of writing for node.
function validate(username, password, callback){
var connection = mysql.createConnection({ user:'foo',
password: 'bar',
database: 'test',
host:'127.0.0.1'});
connection.connect(function (err){
if (err) return callback(new Error('Failed to connect'), null);
// if no error, you can do things now.
connection.query('select username,password from usertable where username=?',
username,
function(err,rows,fields) {
// we are done with the connection at this point), so can close it
connection.end();
// here is where you process results
if (err)
return callback(new Error ('Error while performing query'), null);
if (rows.length !== 1)
return callback(new Error ('Failed to find exactly one user'), null);
// test the password you provided against the one in the DB.
// note this is terrible practice - you should not store in the
// passwords in the clear, obviously. You should store a hash,
// but this is trying to get you on the right general path
if (rows[0].password === password) {
// you would probably want a more useful callback result than
// just returning the username, but again - an example
return callback(null, rows[0].username);
} else {
return callback(new Error ('Bad Password'), null);
}
});
});
};
Related
The Nodejs functions return an error from try/catch scope, such as the one below if the user doesn't exist of if a database is not reachable:
router.delete('/delete/:email', async (req, res) => {
var email = req.params.email;
try {
let result = await User.remove({"email": email});
res.status(204).send(email);
} catch (err) {
res.status(400).send(err);
}
});
I can also return the Error from Nodejs server by myself:
return res.status(400).send(new Error(`The user with email ${email} doesn't exist.`));
The first problem is that I can't find the error message that is embedded somewhere deep in the body the returned Error object. It is stored in one of its 100+ attributes. Where should I look for it so I could display in on a screen for the end user to read it?
Then, the err object generated by the try/catch scope has a set of different attributes comparing to the Error object created with new Error("Here is my error message"). Is there a way to normalize the returned Errors so they all have the same or similar attributes?
You don't need to return the whole error object from the server, and arguably shouldn't since error messages can expose internals about your code and infrastructure.
One way you could handle this is to format and return an error message from the server yourself. Assuming you're using express this would look something like:
return res.status(400).json({ message: `The user with email ${email} doesn't exist.` });
Alternatively you could use an error handling middleware like strong-error-handler found here: https://github.com/strongloop/strong-error-handler which automatically builds a json formatted message that's easier to parse, but keep in mind that the content of the message differs depending on whether you set debug mode to true or no.
If you want to develop a secure web application with nice error handling, i will suggest you the following structure.
Step 1. At front end divide your api calls in four main operations for e.g. inset,update,query and filter.
now whenever your page loads and you want to show some data fetched from server then your api call must be like 'https://domainname.tld/server/query' and send some payload with this api call according to need of your data requirements to be fetched.
At backend probably at Server.js handle like this :
app.all("/server/query", function (req, res) {
try {
console.log(a);
// some database or io blocking process
} catch (error) {
// error handling
var err = writeCustomError(error.message || error.errmsg || error.stack);
res.status(417).json(err).end();
}
});
function writeCustomError(message) {
var errorObject = {};
errorObject.message = message;
errorObject.code = 10001; // as you want
errorObject.status = "failed";
return errorObject;
}
in try block you can also handle logical errors using same function i.e writeCustomError
So if you use this approach you can also implement end-to-end encryption and send only eP('encrypted payload') and eK('encryption Key'),by doing this end users and bad end users even can not evaluate your serve API calls.
If you are thinking how will you route different paths at server then simplest solution is send uri in payload from client to server for e.g
User wants to reset password :-
then
call api like this
https://domain.tld/server/execute and send Json object in payload like this {uri:"reset-password",old:"",new:""}.
at backend
use
app.all("/server/execute", function (req, res) {
try {
// decrypt payload
req.url = payload.uri;
next();
} catch (error) {
// error handling
var err = writeCustomError(error.message || error.errmsg || error.stack);
res.status(417).json(err).end();
}
});
app.all("/reset-password", function (req, res) {
try {
// reset logic
} catch (error) {
// error handling
var err = writeCustomError(error.message || error.errmsg || error.stack);
res.status(417).json(err).end();
}
});
so in this way only developer know where password reset logic and how it can called and what parameters are required.
I will also suggest you to create different router files for express like QueryRouter,InsertRouter etc.
Also try to implement end-to-end encryption.Any query regarding post,kindly comment it.
I am trying to create a very simple registration method on my project but I am having trouble figuring out how to stop postgres from adding in people with the same email. I am using postgres and Node.js.
I have an add function that I want to return false my postgres table already has a user with the email he/she tried using. I do the following:
function checkExistingEmail(email, cb){
pg.connect(cstr, function(err, client, done){
if(err){
cb(err);
}
else{
var str = 'SELECT email from Swappers where email=$3';
client.query(str, function(err, result){
if(err){
cb(err);
}
else{
console.log(result.row.email);
if(result.row.email === undefined){
cb(false);
}
else{
cb(true);
}
}
});
}
});
}
Now when I display result.row.email to the console I get that it is undefined. Which is what I want for the first time user, so it should return true, and I should be able to add the user to the database and move on. But that is not the case.
In a file I have called users.js I have the following route handler:
router.post('/authnewuser', function(req,res){
// Grab any messages being sent to use from redirect.
var authmessage = req.flash('auth') || '';
var name = req.body.username;
var password = req.body.password;
var email = req.body.email;
db.checkExistingEmail(email, function(data){
if(data === true)
console.log('success');
else
console.log('fail');
});
});
Now When I run this and try registering the functionality I want is not working. I was wondering if is has to go with my checkExistingEmail function and if I am using results.row.email correctly. Right now When I run this code I just keep getting that it has failed. Which is not what I want. it should be returning true for a new user with an email that has never been saved into the db before.
This is usually not the way to go with a database. Checking first always requires two round-trips to the database. Instead,
put a unique constraint on the "email" column,
just insert the data, and
handle the error you'll get with a duplicate email.
Most inserts will just succeed--one round-trip to the database. And you have to handle errors anyway--there's a lot of reasons an INSERT can fail. So there's not a lot of additional code to write for this specific error.
I'm aware of the best practice of MongoDB connection pooling in NodeJS of the singleton DB connection type like this
var db = null;
var connection = function getDBConnection(callback) {
if(db) { callback(null, db) } else { MongoClient.connect( .... ) }
}
module.exports = getDBConnection;
However, what I cannot get my head around at the moment is how to handle this in a one-shot script that, say, does some pre-initialization on the documents of a certain db collection:
getDBConnection(function (err, database) {
var collection = database.collection("objects");
var allObjectsArray = collection.find( /* ... */
).toArray(function (err, objects) {
if(err != null) console.log(err);
assert.equal(null, err);
_.each(objects, function (item) {
collection.update(
{ id: item.id},
{ $set: { /* ... */ }},
function (err, result) {
if(err != null) console.log(err);
assert.equal(null, err);
}
);
});
// database.close(); <-- this fails with "MongoError: Connection Closed By Application", thrown by the update callback
});
// database.close(); <-- this fails too, thrown by the toArray callback
});
If I call the script like that, it never terminates, due to the still open connection. If I close the connection at the bottom, it fails because of, well, a closed connection.
Considering that opening a new connection for every update is not really an option, what am I missing? Keeping the connection open may be fine for webapps, but for a one-shot script called from a shell script this really doesn't work out, does it?
Sorry if this question has arisen before, I've given it some research but have not quite been able to come up with a working answer for me...
Thanks!
Julian
As a "pooled connection" there is code running to keep the connection alive and establish more connections in the pool if required under the driver connection. So much like various "server code" methods, event loop handlers have been invoked and the process does not exit at the end of your code until these are de-registered.
Therefore your two choices to call after all your code has executed are either:
Call db.close() or in your code context specifically database.close() once all is done.
Call process.exit() which is a generic call in node.js applications which will shut the whole process down and therefore stop any other current event loop code. This actually gives you an option to throw an error on exit if you want your code to be "shell integrated" somewhere and look for the exit status.
Or call both. db.close() will allow execution to the next line of code and whatever you put there will also run.
But you have to wait until everything is called, so you can cannot use synchronous loops with asynchronous code in the middle:
async.each(objects,function(item,callback) {
collection.update(
{ "_id": item._id },
{
// updates
},
callback
);
},function(err) {
if (err) throw err;
database.close();
});
I have a database query (function) which is asynchronous, and as a result I need to use a callback function (no problem with that). However, in Node.js I need to make two separate queries in the same POST function. Both are asynchronous, so I'm having trouble on how to continue with the execution of the POST.
Goal:
Validate form entries for malformations, etc.
Check if username exists in db before saving (must be unique)
Check if email exists in db before saving (must be unique)
Save user if everything checks out, else throw some errors
Normally, I would have something like this (oversimplified):
postSearch = function(req, res, next) {
var searchCallback = function(err, results) {
// Do stuff with the results (render page, console log, whatever)
}
// This is the db query - async. Passes search results to callback
defaultSearch(input, searchCallback);
}
Which only has one async query, so only one callback. Normally I would just get the db results and render a page. Now I have to validate some form data, so my POST function looks something like this:
postUser = function(req, res, next) {
// Some static form validation (works, no issues)
var usernameExistsCallback = function(err, exists) {
// Does the username exist? True/false
}
// DB query - passes true or false to the callback
usernameExists(username, usernameExistsCallback);
var emailExistsCallback = function(err, exists) {
// Does the email exist? True/false
}
// DB query - passes true or false to the callback
emailExists(email, emailExistsCallback);
// Check if ALL validation constraints check out, implement error logic
}
The node-postgres module is async, and as a result the queries need callbacks (if I want to return any value, otherwise I can just run the query and disconnect). I have no problem executing both of those queries. I can console.log() the correct results in the callbacks. But now I don't know how to access those results later on in my postUser function.
I've read all about async JavaScript functions, but I've been scratching my head on this one for three hours now trying ridiculous things (like setting global variables [oh my!]) to no avail.
The results I need from these two queries are simply true or false. How can I organize this code to be able to use these results in the postUser function? It seems to me that I need something like a third callback, but I have no clue how to implement something like that. Is it necessary for me to start using async? Would it be a good idea? Nothing in this application is super complex thus far, and I'd like to keep dependencies low <-> it makes sense.
How about this:
postUser = function(req, res, next) {
// Some static form validation (works, no issues)
var emailExistsCallback = function(err, exists) {
// Does the email exist? True/false
var usernameExistsCallback = function(err, exists) {
// Does the username exist? True/false
// DO STUFF HERE
}
// DB query - passes true or false to the callback
usernameExists(username, usernameExistsCallback);
}
// DB query - passes true or false to the callback
emailExists(email, emailExistsCallback);
// Check if ALL validation constraints check out, implement error logic
}
Simplest way is to nest functions like this:
postUser = function(req, res, next) {
var emailExistsCallback = function(err, exists) {
// Does the email exist? True/false
// Check if ALL validation constraints check out, implement error logic
next(); // <= you should finally call "next" callback in order to proceed
}
var usernameExistsCallback = function(err, exists) {
// Does the username exist? True/false
emailExists(email, emailExistsCallback); // <= note this
}
usernameExists(username, usernameExistsCallback);
}
Or you can use async, Q, seq or yaff(which is Seq reimplemented). There are number of libs to make your life easier. Better to try them all and decide which one is right for you, your style, requirements and so on.
you can use a common var to keep track of how many responses you got back. if you have them both, you can then do the stuff that needs them in a third "callback", which i called done():
postUser = function(req, res, next) {
var hops=0, total=2;
function done(){
// do stuff with both username and email
}
// Some static form validation (works, no issues)
var usernameExistsCallback = function(err, exists) {
if(++hops>=total && exists ){ done(); }
// Does the username exist? True/false
}
// DB query - passes true or false to the callback
usernameExists(username, usernameExistsCallback);
var emailExistsCallback = function(err, exists) {
if(++hops>=total && exists){ done(); }
// Does the email exist? True/false
}
// DB query - passes true or false to the callback
emailExists(email, emailExistsCallback);
// Check if ALL validation constraints check out, implement error logic
}
you should probably add error handling as needed by your app, specifically in both of the SQL callbacks, but this is a nice parallel IO ajax pattern that should do what you need.
I'm using the Node Express framework to build an API and I run into a problem regarding the Basic Auth functionality. I need to run an SQL query to retrieve information about a user and validate their credentials. The issue occurs after the query has been completed. The SQL data is sent into a callback function as shown below. I want to do all the validation inside that callback but I want to break out of the SQL callback and return true/false from the express.basicAuth() function. I have tried setting a global variable and then accessing it outside of the SQL callback but sometimes the query might not have finished by the time that it gets the block that accesses that global variable. Thanks in advance for your help.
var auth = express.basicAuth(function(user, pass) {
// Query to select information regarding the requested user
/* Query here to find the requested user's data */
client.query(query, function (err, rows, fields) {
if (err) throw err;
GLOBAL.sql = rows;
/* I want to break out of this query callback function and return true from this auth variable */
});
// Sometimes the query isn't completed when it gets to this stage
console.log(JSON.stringify(GLOBAL.sql));
});
express.basicAuth also supports asynchronous operation:
var auth = express.basicAuth(function(user, pass, next) {
...
client.query(query, function (err, rows, fields) {
if (err)
next(err);
else
if (/* authentication successful */)
next(null, user); // <-- sets 'req.remoteUser' to the username
else
next(null, false);
});
});