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.
Related
I'm a newbie at node.js, and trying to make a login page.
When I'm trying to login with the right credentials the page works as intended. Also worth noting is that when I try to login with no credentials the alert window pops up. But when I try to login with the wrong credentials, it just won't work. I've tracked the error back to "alert" function, but I cannot understand why in the world the alert function works when calling it to display the alert that no username nor password was inserted, but will crash when I'm trying to display that the username and password are wrong. I'm pretty certain that the error comes from the alert function.
The code is below.
Thanks alot!
app.post('/auth', function(request, response) {
var username = request.body.username;
var password = request.body.password;
if (username && password) {
connection.query('SELECT * FROM accounts WHERE username = ? AND password = ?', [username, password], function(error, results, fields) {
if (results.length > 0) {
request.session.loggedin = true;
request.session.username = username;
response.redirect('/home');
response.end();
} else {
alert('Incorrect Username and/or Password!');
}
});
} else {
alert('Please enter Username and Password!');
}
});
but I cannot understand why in the world the alert function works when calling it to display the alert that no username nor password was inserted
It shouldn't do.
alert isn't a function provided by Node.js. It belongs to browsers so it can show something in the browser UI.
To send something from a server built on Node.js back to the browser then:
The something needs to be data
You need to send it by calling a method (like render, json or send) on the response object.
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.
so my question is very specific. Whenever I run this bit from my page I get an error if I don't input the CORRECT ID I need to search for in the API. It doesn't know what to do when it doesn't make a valid API call because the query string is incorrect. How do I go about redirecting to a different page WHEN there's an error like that or how do I prevent it from STOPPING the program? I'm assuming there's a try catch in here but I tried it multiple different ways and I'm still confused because it doesn't work. Help please! I'm new to this... Here's the snippet. The request portion of the code is where the error occurs if the "bnetID" is not a valid ID. If it is valid it runs perfectly fine...
// Make a GET request to the /results page (When submit is pressed)
app.get("/results", function(req, res){
// Retrieve bnetID and REGION from the FORM
var bnetID = req.query.bnetID;
var region = req.query.region;
// Replace the # with a -
bnetID = bnetID.replace("#", "-");
// Create the query string
var url = "http://ow-api.herokuapp.com/profile/pc/"+ region +"/"+bnetID;
// Make the API request
request(url, function(err, response, body){
if(err){
console.log(err);
} else {
var playerData = JSON.parse(body);
playerData = findImportantData(bnetID, playerData);
checkIfExists(bnetID, playerData);
res.render("results", {data: playerData});
}
})
});
Why don't you handle what you want to do if there is an error?
if(err){
console.log(err); // change this to whatever you want to do
}
I am trying to redirect a page to my home page (with the route '/search') after submitting a form. In my submit.html file, I have a form and when the submit button is pressed the data in the form is submitted via the '/submit' post method. In my index.js file, I have a get and post function for '/submit' so that I can access the MongaDB and collection. Here are the functions:
//getting info from the database
router.get('/submit', function(req, res) { //RETURN JSON OF INTINERARIES
var db = req.db; //Creates a variable called db, which equals the database called db (db holds the collegelist collection)
var collection = db.get('collegelist'); //Creates a variable called collection which accesses the collection called collegelist
});
router.post('/submit', function(req, res){
var url = 'mongodb://localhost:27017/maptest'; //IDENTIFIES THE MONGO DB
//var url = 'mongodb://dbuser2:sillydoo#ds059195.mlab.com:59195/heroku_vmz14q76';
function insertDocument(db, record, callback) { //this creates a function to insert data into collegelist
db.collection('collegelist').insertOne(record,
function(err, result) {
assert.equal(err, null); //error must equal null
console.log("Function for inserting a document.");
callback(result); //calling back on the result?
});
};
//this grabs the data from the form using ids and assigns it to the parameters in the collegelist database
req.body['name'] = req.body.name; //INSERTING THE EMAIL INTO THE FIELDS THAT ARE COLLECTED
//connects to the mongodatabase (the variable url equals the database -- either mongolab or local)
MongoClient.connect(url, function(err, db) { //MONGO CLIENT IS CONNECTING TO THE URL -- TWO POSSIBLE OUTCOMES: ERROR OR THE DB
assert.equal(null, err); //ERROR MUST BE NULL FOR THE PROGRAM TO CONTINUE
insertDocument(db, req.body, function(result) { //this calls on the insert document function I just created
//RECORD IS CALLED REQ.BODY IN THE LINE ABOVE
db.close(); //CLOSE CONNECTION WITH THE DB
console.log("DB Result :", result); //LOGGING IT!
//ALL THE CODE IN THIS ANNONYMOUS FUNCTION IS THE CALLBACK IN THE INSERTDOCUMENT FUNCTION
res.send('');
});
})
res.redirect('/search');
//res.render('search', { username: req.user.givenName });
});
At the end of the function I tried to call res.redirect('/search'); and it returned the error: Error: Can't set headers after they are sent. After doing research I realized this error is occurring because I am in the Body or Finished state. However, I can't figure out what I need to write instead to redirect the page to my '/search' route or where I can write res.redirect('/search') so that it doesn't return this error.
Any help is greatly appreciated! Thank you in advance!
Check this answer, You can't send multiple response.
Here, remove res.send if it's not necessary
Replace res.send(''); in the insertDocumentcallback with res.redirect('/search');. If you don't want to wait while DB stuff completed than just remove res.send('');
this is because you are sending response twice.
one at
console.log("DB Result :", result); //LOGGING IT!
//ALL THE CODE IN THIS ANNONYMOUS FUNCTION IS THE CALLBACK IN THE INSERTDOCUMENT FUNCTION
res.send('');
and one at the bottom as
res.redirect('/search');
Remove res.send and you'll be fine. always make sure that you only send response once.
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);
}
});
});
};