How to redirect using Node JS? - javascript

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.

Related

Node.js flat-cache, when to clear caches

I have a Node.js server which queries MySQL database. It serves as an api end point where it returns JSON and also backend server for my Express application where it returns the retrieved list as an object to the view.
I am looking into implementing flat-cache for increasing the response time. Below is the code snippet.
const flatCache = require('flat-cache');
var cache = flatCache.load('productsCache');
//get all products for the given customer id
router.get('/all/:customer_id', flatCacheMiddleware, function(req, res){
var customerId = req.params.customer_id;
//implemented custom handler for querying
queryHandler.queryRecordsWithParam('select * from products where idCustomers = ? order by CreatedDateTime DESC', customerId, function(err, rows){
if(err) {
res.status(500).send(err.message);
return;
}
res.status(200).send(rows);
});
});
//caching middleware
function flatCacheMiddleware(req, res, next) {
var key = '__express__' + req.originalUrl || req.url;
var cacheContent = cache.getKey(key);
if(cacheContent){
res.send(cacheContent);
} else{
res.sendResponse = res.send;
res.send = (body) => {
cache.setKey(key,body);
cache.save();
res.sendResponse(body)
}
next();
}
}
I ran the node.js server locally and the caching has indeed greatly reduced the response time.
However there are two issues I am facing that I need your help with.
Before putting that flatCacheMiddleware middleware, I received the response in JSON, now when I test, it sends me an HTML. I am not too well versed with JS strict mode (planning to learn it soon), but I am sure the answer lies in the flatCacheMiddleware function.
So what do I modify in the flatCacheMiddleware function so it would send me JSON?
I manually added a new row to the products table for that customer and when I called the end point, it still showed me the old rows. So at what point do I clear the cache?
In a web app it would ideally be when the user logs out, but if I am using this as an api endpoint (or even on webapp there is no guarantee that the user will log out the traditional way), how do I determine if new records have been added and the cache needs to be cleared.
Appreciate the help. If there are any other node.js caching related suggestions you all can give, it would be truly helpful.
I found a solution to the issue by parsing the content to JSON format.
Change line:
res.send(cacheContent);
To:
res.send(JSON.parse(cacheContent));
I created cache 'brute force' invalidation method. Calling clear method will clear both cache file and data stored in memory. You have to call it after db change. You can also try delete specified key using cache.removeKey('key');.
function clear(req, res, next) {
try {
cache.destroy()
} catch (err) {
logger.error(`cache invalidation error ${JSON.stringify(err)}`);
res.status(500).json({
'message' : 'cache invalidation error',
'error' : JSON.stringify(err)
});
} finally {
res.status(200).json({'message' : 'cache invalidated'})
}
}
Notice, that calling the cache.save() function will remove other cached API function. Change it into cache.save(true) will 'prevent the removal of non visited keys' (like mentioned in comment in the flat-cache documentation.

How do I do a try/catch for my specific API Call example?

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
}

How do I specify MongoDB key/value parameters in an $http.get with an AngularJS controller?

I'm using the MEAN stack for a web app. In my controller.js, I have the following:
var refresh3 = function() {
$http.get('/users').success(function(response) {
console.log("I got the data I requested");
$scope.users = response;
$scope.contact3 = "";
});
};
refresh3();
This pulls back every object in the "users" collection from my MongoDB. How could I add parameters to this to bring back, for example, only objects where "name" : "Bob" ? I have tried adding parameters in the '/users' parentheses using:
$http.get('/users', {params:{"name":"Bob"}})
I've also tried variants of that, but no luck. Any help would be appreciated!
If your server is receiving the data
(and it should, as $http.get('/users', {params:{"name":"Bob"}}) is correct)
On server side, make use of the query string:
req.query
like so:
app.get('/users', function(req,res){
if(req.query.name){
db.users.find({"name":req.query.name},function (err, docs) { console.log(docs); res.json(docs); });
}
else{
db.users.find(function (err, docs) { console.log(docs); res.json(docs); });
}
});
WHAT WAS THE ISSUE?
You hinted in your comments that your server was set to respond to the app.get('/users') GET request like so:
db.users.find(function (err, docs) {
// docs is an array of all the documents in users collection
console.log(docs); res.json(docs); }); });
So I believe that your angularjs $http get is correct, and your server is receiving the parameters {"name":"Bob"} as it should;
it just doesn't know what to do with them:
all it is set to do is to return the whole collection in the particular case of a app.get('/users') GET request.
HOW TO CONFIGURE YOUR SERVER FOR REST
You do not have to re-invent the wheel on the server.
Rather, you could consider using a middleware to automate the task (in the present case, the task is to issue a proper MongoDb request when you receive a get query with parameters from the client)
e.g. express-restify-mongoose middleware

How to query postgres database for existing email

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.

Node.js - Break out of callback function and return true/false in the parent functon

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);
});
});

Categories

Resources