How to send response to front end after execution of mongodb request? - node.js

I am creating sign up page. Where, I first check whether user email already present in our mongodb database or not. If it is present then I want to send error message to frontEnd. However, I am failing to do that, I think it might be because of asynchronous behavior of JavaScript.My Code is as following:
var myObj , myJSON
var SignUpUserEmail, SignUpUserPassword, SignUpUserName, SignUpErr
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var q = url.parse(req.url, true).query
SignUpUserEmail = q.SignUpUserEmail
SignUpUserPassword = q.SignUpUserPassword
SignUpUserName = q.SignUpUserName
MongoClient.connect("mongodb://localhost:27017/ABC",function(err,
database) {
if (err) throw err;
var db=database.db('ABC')
let findOneParam = {"UserEmail":SignUpUserEmail}
db.collection('Profiles').findOne(findOneParam, function(err, result) {
if (err) throw err;
if(!result) {
db.collection('Profiles', function(err, collection){
if (err) throw err;
collection.insertOne({"UserId":"ProfileA0001",
"UserEmail":SignUpUserEmail,
"UserPassword":SignUpUserPassword,
"UserName":SignUpUserName,
"IsEmailAuthenticated":"false"
}, function(err, res){
if (err) throw err;
SignUpErr = "document inserted"
console.log("SignUpErr inside:", SignUpErr)
})
})
} else {
SignUpErr = "Email already has been registered."
console.log("SignUpErr inside:", SignUpErr)
}
})
})
console.log("SignUpErr outside:", SignUpErr)
myObj = {"SignUpErr":SignUpErr};
myJSON = JSON.stringify(myObj);
res.end(myJSON);
}).listen(9000);
Note: "SignUpErr inside:" giving correct result. however, "SignUpErr outside:" shows it as undefined.

Note: "SignUpErr inside:" giving correct result. however, "SignUpErr outside:" shows it as undefined.
This is because of the asynchronous nature of the nodejs. SignUpErr will be undefined until the time it is initialized within the db.collection('Profiles',function(){}) call.
So, to fix this, you need to send response within db.collection('Profiles',function(){}). that's, after the initilization.
Making those changes to your code,
'use strict';
const http = require('http');
http.createServer(function (req, res) {
res.statusCode = 200; // Setting the status code
res.setHeader('Content-Type', 'text/plain'); // Setting the content-type for response
let {SignUpUserEmail, SignUpUserPassword, SignUpUserName} = url.parse(req.url, true).query;
MongoClient.connect("mongodb://localhost:27017/ABC", function (err, database) {
if (err) {
throw err;
}
let db = database.db('ABC');
db.collection('Profiles').findOne({
UserEmail: SignUpUserEmail
}, function (err, result) {
if (err) {
throw err
}
if (result) {
let msg = "Email already has been registered.";
console.log("SignUpErr inside:", msg);
return res.end(JSON.stringify({
SignUpErr: "document inserted"
}));
}
db.collection('Profiles', function (err, collection) {
if (err) throw err;
collection.insertOne({
"UserId": "ProfileA0001",
"UserEmail": SignUpUserEmail,
"UserPassword": SignUpUserPassword,
"UserName": SignUpUserName,
"IsEmailAuthenticated": "false"
}, function (err, dbresult) {
if (err) {
throw err;
}
let msg = "document inserted";
console.log("SignUpErr inside:", msg);
return res.end(JSON.stringify({
SignUpErr: "document inserted"
}));
})
});
});
});
}).listen(9000);

I usually use express as my web framework which comes with res.send() method, where you can send your response . I usually build a JSON response, and send it as res.send(JSON.stringify(data)); There is also res.JSON(data).
If you wish to use HTTP module , then you can use res.end() method.
Details are provided here . Hope this helps.

Related

Cannot set headers after they are sent to clients in node.js

My code is not working . I am beginner and don't know my problem. Kindly help.I have seen one or two solution on stackoverflow but didnot get .
This is code.
app.post('/post',(request,response)=>{
var description=request.body.description;
var contact_number=request.body.contact_number;
var city=request.body.city;
var budget=request.body.budget;
var category=request.body.optradio;
var query=connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)",[null,description,category,city,contact_number,budget],function(err){
if(err)
console.log(err);
else
response.send("successful");
});
response.redirect('/data');
});
app.get('/data',function(request,response){
connection.query("SELECT * FROM jobs ORDER BY Jobs_id DESC",(err, rows,fields) => {
if(err) {
console.log(err);
}
else {
response.render('feed', {title : 'Jobs Details',
items: rows })
}
});
});
app.listen(3000);
This is the error
pp.post('/post', (request, response) => {
var description = request.body.description;
var contact_number = request.body.contact_number;
var city = request.body.city;
var budget = request.body.budget;
var category = request.body.optradio;
var query = connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)", [null, description, category, city, contact_number, budget],
function (err) {
if (err) {
console.log(err);
} else {
response.redirect('/data');
}
});
});
app.get('/data', function (request, response) {
connection.query("SELECT * FROM jobs ORDER BY Jobs_id DESC", (err, rows, fields) => {
if (err) {
console.log(err);
}
else {
response.render('feed', {
title: 'Jobs Details',
items: rows
})
}
});
});
app.listen(3000);
There can be only one response to single HTTP request. In your code, you are first trying to send response with
response.send("successful");
but this on its own doesn't break the flow of the function which means that if the condition is actually met then this will execute and the execution continues and finds another response, in this case
response.redirect('/data');
and it will try to send another response to the original http request but at this point it is already too late because one response has already been send.
To solve this issue in general, you can place return in front of any line of code that is closing the the connection (response.send, response.redirect, ...). That way, the function's execution is terminated at the first response, whichever it is.
So you could do something like
var query=connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)",[null,description,category,city,contact_number,budget],function(err){
if(err)
console.log(err);
else
return response.send("successful");
});
return response.redirect('/data');
});

Error: Can't set headers after they are sent in loop multiple request

i'm beginner at nodejs, i got a problem when request multiple url in a loop then i render it.
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:)
router.get('/', function(req, res, next) {
setInterval(function(){
request(url1,function (error,response,body) {
var data1 = JSON.parse(body);
request(url2+data1.access_token,function (error,response,body) {
var data_info = JSON.parse(body);
//error when it render
res.render('index', {data_info : data_info});
})
})
},5000);
});
That's not exactly a loop, I understand you mean that you call the same function repeteadly with setInterval().
Once you've sent your first response with res.render(), which finishes the response process for that request, subsequent attempts to use that res object fail.
If you want to send data to the client in 5 seconds interval you should probably either look into websockets or pass the setInterval() calls to the client so it polls your server each 5 seconds, in which case your server code could be changed to:
router.get('/', (req, res) => {
request(url1, (error, response, body) => {
const data1 = JSON.parse(body);
request(`${url2}${data1.access_token}`, (error, response, body) => {
const data_info = JSON.parse(body);
res.render('index', { data_info });
});
});
});
You can make use of Async Module
const async = require('async');
router.get('/', function (req, res, next) {
async.waterfall([
function(callback) {
request(url1, function (error,response,body) {
if(err) {
callback(err)
}else {
var data1 = JSON.parse(body);
callback(data1)
}
})
},
function(data1, callback) {
request(url2+data1.access_token, function(error,response,body) {
if(err) {
callback(err)
}else {
var data_info = JSON.parse(body);
callback(null, data_info)
}
})
}
], function(err, result) {
if(err) {
res.json({success: false, error: err, message: "Something went wrong.!"})
}else {
res.render('index', {
data_info : result
});
}
})
})

Express GET Request Results in Error: "res.send is not a function"

I am trying to get data from a SQL Server DB using node. I can make a connection and get data by running functions, but I would like to turn the functions into API endpoints.
Based on the error it seems to me that the res variable isn't getting passed down into the last if statement, but I'm not seeing the issue.
I get a res.send is not a function error when using a GET method on this address from Postman.
let mssqlQuery = function(query, res) {
sql.connect(dbConfig, function(err) {
if (err) {
console.log("Error while connecting database :- " + err)
res.send(err)
} else {
let request = new sql.Request();
request.query(query, function(err, res) {
if (err) {
console.log("Error while querying database :- " + err)
res.send(err)
} else {
res.send(res) // res.send is not a function
}
})
}
})
}
// GET API
app.get("/api/address", function(req, res) {
var query = "select * from address"
mssqlQuery(query, res)
})
Is the res variable improperly scoped or might I have the wrong approach entirely?
As #Sirko suggested, the res value was shadowed by an other variable. The corrected code:
let mssqlQuery = function(query, res) {
sql.connect(dbConfig, function(err) {
if (err) {
console.log("Error while connecting database :- " + err)
res.send(err)
} else {
let request = new sql.Request();
request.query(query, function(err, resp) { // Changed res to resp
if (err) {
console.log("Error while querying database :- " + err)
res.send(err)
} else {
res.send(resp) // res.send is not a function
}
})
}
})
}

Unable to run a function synchronously in nodejs and express

I have used wikipedia-js for this project. This is my code for summary.js file.
var wikipedia = require("wikipedia-js");
var something = "initial";
module.exports = {
wikitext: function(topicname) {
console.log("Inside wikitex funciton :" + topicname);
var options = {
query: topicname,
format: "html",
summaryOnly: false,
lang: "en"
};
wikipedia.searchArticle(options, function(err, htmlWikiText) {
console.log("Inside seararticlefunciton :");
if (err) {
console.log("An error occurred[query=%s, error=%s]", topicname, err);
return;
}
console.log("Query successful[query=%s, html-formatted-wiki-text=%s]", topicname, htmlWikiText);
something = htmlWikiText;
});
return something;
},
};
This module I am using in /wiki/:topicname route. The corresponding code in index.js is like this.
router.get('/wiki/:topicname', function(req, res, next) {
var topicname = req.params.topicname;
console.log(topicname);
var first = summary.wikitext(topicname);
res.send("Hello "+first);
});
The problem is, everytime i visit a wiki/some-topic, the last return statement of summary.js executes before htmlWikiText is populated with content. So I always see hello initial on the browser page. Although after sometime it gets printed on terminal due to console.log statement.
So how should I resolve this issue?
I'm not going to try turning this code into synchronous. I'll just correct it to work as an asynchronous version.
You need to pass in callback to wikitext() and return the value in that callback. Here is the revised code of wikitext() and the route that calls it:
var wikipedia = require("wikipedia-js");
module.exports = {
wikitext: function(topicname, callback) {
console.log("Inside wikitex funciton :" + topicname);
var options = {
query: topicname,
format: "html",
summaryOnly: false,
lang: "en"
};
wikipedia.searchArticle(options, function(err, htmlWikiText) {
console.log("Inside seararticlefunciton :");
if (err) {
console.log("An error occurred[query=%s, error=%s]", topicname, err);
return callback(err);
}
console.log("Query successful[query=%s, html-formatted-wiki-text=%s]", topicname, htmlWikiText);
callback(null, htmlWikiText);
});
}
};
router.get('/wiki/:topicname', function(req, res, next) {
var topicname = req.params.topicname;
console.log(topicname);
summary.wikitext(topicname, function(err, result) {
if (err) {
return res.send(err);
}
if (!result) {
return res.send('No article found');
}
res.send("Hello "+result);
});
});

Node.JS / JavaScript Async Call back issue

I am trying to accomplish the following (should be quite basic and I must be missing something trivial):
Call a function with string that has a select statement
Wait until the DB call completes and the rows (or json equivalent) is returned
Populate http object to return back
Here is code:
util.js
exports.execute = function( query){
if (connection) {
connection.query(query, function(err, rows, fields) {
if (err) throw err;
console.log("from Util - " + JSON.stringify(rows));
return JSON.stringify(rows);
});
}
};
repo.js
var q = "select * from xxx";
var response;
util.execute(q, function (err, r){
if (err){
throw err;
console.log(err);
}
else {
console.log(r);
res.contentType('application/json');
res.write(r);
res.end();
}
});
My problem is while the code within util.js is called and I can see the json in console, it never comes back to the anonymous call back function in the repo.js.
What am I doing wrong here ?
Update
Thanks Ben
I also found the solution in same line ... here is new code:
repo.js:
var send_data = function (req, res, r){
res.contentType('application/json');
res.write(r);
res.end();
}
exports.all = function(req, res){
var q = "select * from XXX";
var response;
util.execute(req, res,q, send_data);
};
util.js:
exports.execute = function(req, res, query, callback){
if (connection) {
connection.query(query, function(err, rows, fields) {
if (err) throw err;
callback(req, res, JSON.stringify(rows)) ;
});
}
};
util.execute only accepts one parameter in your code. It needs to accept a second callback parameter in order to use it the way you do. (Callbacks aren't magic, they're just function calls)
Something like:
exports.execute = function(query,callback){
if (connection) {
connection.query(query, function(err, rows, fields) {
if (err) throw err;
console.log("from Util - " + JSON.stringify(rows));
callback(null,JSON.stringify(rows));
});
}
};
If you'd like it to behave consistently and accept an error parameter, you might want fill that in:
exports.execute = function(query,callback){
if (connection) {
connection.query(query, function(err, rows, fields) {
callback(err,null);
console.log("from Util - " + JSON.stringify(rows));
callback(null,JSON.stringify(rows));
});
}
};

Resources