I wrote a simple CRUD Api in node.js. I keep getting a write after end on all of my POST, PUT and DELETE functions. I have lost all sense of trying to trouble shoot this thing and was hoping for a fresh pair of eyes or some advice on trying to track it down. GET works perfectly fine and uses the same code sendJSON() in httpmgs.js.
I have scattered all kinds comments around trying to figure out where the error is happening. I didn't know if the req.on("end".... was causing an issue so I have rewritten that part to no avail.
controller.js:
switch (req.method){
case "GET":
if(req.url === "/staff"){
staff.getList(req, resp);
}
break;
case "POST":
if (req.url === "/staff/add"){
var reqBody = '';
req.on("data", function (data){
reqBody += data;
if(reqBody.length > 1e7){
msg.show413(req, resp);
}
});
req.on("end", function() {
console.log(req.data)
staff.add(req, resp, reqBody)
});
}
break;
case "PUT":
if (req.url === "/staff/update"){
var reqBody = '';
req.on("data", function (data){
reqBody += data;
if(reqBody.length > 1e7){
msg.show413(req, resp);
}
});
req.on("end", function() {
staff.update(req, resp, reqBody);
});
}
else{
msg.show404(req,resp);
}
break;
staff.js:
exports.add = function (req, resp, reqBody){
try{
if (!reqBody) throw new Error("Input not valid");
var data = JSON.parse(reqBody);
if (data){
db.executeSql("SELECT MAX(ID) AS ID FROM jarvisdb.staff",function (maxID, err){
if(err){
msg.show500(req, resp, err);
}
else{
var newID = maxID[0].ID+1
var sql = "INSERT INTO jarvisdb.staff (`ID`, `First Name`, `Last Name`) VALUES";
sql+= util.format("('%d' ,\"%s\", \"%s\")", newID, data.firstName, data.lastName);
db.executeSql(sql, (data, err)=>{
if(err){
msg.show500(req, resp, err)
}
else{
console.log('Before send')
msg.sendJSON(req,resp,data)
console.log('After send')
}
})
}
});
}
else{
throw new Error("Input not valid");
}
}
catch (ex) {
console.log('500')
msg.show500(req, resp, ex);
}
};
httpMsgs.js:
exports.sendJSON = function(req,resp,data){
if(data){
console.log('Before Write')
resp.writeHead(200, {"Content-type" : "application/json"});
console.log('Write Head')
resp.write(JSON.stringify(data));
console.log('Write body')
resp.end();
console.log('end');
}
}
Expected out:
No errors and sends back JSON
Actual results:
Listening on port 9000....
undefined
Before send
Before Write
Write Head
Write body
end
After send
events.js:174
throw er; // Unhandled 'error' event
^
Error [ERR_STREAM_WRITE_AFTER_END]: write after end
at write_ (_http_outgoing.js:572:17)
at ServerResponse.write (_http_outgoing.js:567:10)
at Object.exports.sendJSON (E:\JARVIS\API\peak-2.0\httpMsgs.js:60:14)
at db.executeSql (E:\JARVIS\API\peak-2.0\controllers\staff.js:53:33)
at Execute.conn.execute [as onResult] (E:\JARVIS\API\peak-2.0\db.js:35:9)
at process.nextTick (E:\JARVIS\API\peak-2.0\node_modules\mysql2\lib\commands\query.js:76:16)
at process._tickCallback (internal/process/next_tick.js:61:11)
Emitted 'error' event at:
at writeAfterEndNT (_http_outgoing.js:634:7)
at process._tickCallback (internal/process/next_tick.js:63:19)
There is no
break;
after your case. So, all cases beyond the current matched case will be executed sequentially until the end.
EDIT
Try restarting your SQL server
UPDATE
You have two options :
In your sendJSON function use:
OPTION 1 (Without Express):
resp.writeHead('Content-Type', 'application/json');
resp.end(JSON.stringify(data));
OR
OPTION 2 (With Express):
Here you don't need to specify the header type
res.json(data);
Related
here is the code of index.js file
var request = require('request');
var requestHandling = require('../routes/request_handling_functions');
router.get("/example1", function (req, res) {
var result =
requestHandling.requestMethodGet('http://localhost:8083/getUserInfo/865c2c25-
d9e7-412d-a064-326bd66c9e9c', res);
console.log("===RESULT=====");
console.log(result);
});
in above code I want that function requestMethodGet return the result into result variable then I manipulate the result according to my need then show to user and also I am console my return result.
but here is the problem with it because Node.js is asynchronous language so first it print the result then it call the function requestMethodGet that is so irritating.
Here is the code of requestMethodGet
requestMethodGet: function (url, res) {
//SET ALL THESE PARATMETER TO MAKE REQUEST
request.get({url: url}, function (e, r, body) {
var errorResult = module.exports.validateResponseeData(e);
console.log("====errorResult===in===Get==method====");
console.log(errorResult);
if (errorResult != "continue") {
console.log("===im in not continue");
return errorResult;
} else {
//LOGING THE RESPONSE BODY
log.info('body:', body);
var responseData = JSON.parse(body);
console.log("======RESPONSE=========DATA=====================");
console.log('error:', e);
console.log('statusCode:', r && r.statusCode);
console.log('body:', body);
console.log("====================================");
console.log(responseData);
return responseData;
}
});
}
I want that the router get method run the code in the sequence as the code write. but I search it everywhere I not found the any solution so come here to find my solution.
if any information is needed to solve this question then please inform me.
Try the following. It returns a promise from your requestMethodGet function and you then wait until that is resolved before logging the response. I suggest you read more on Promises to understand how this works.
requestMethodGet: function (url, res) {
return new Promise((resolve,reject) => {
//SET ALL THESE PARATMETER TO MAKE REQUEST
request.get({url: url}, function (e, r, body) {
var errorResult = module.exports.validateResponseeData(e);
console.log("====errorResult===in===Get==method====");
console.log(errorResult);
if (errorResult != "continue") {
console.log("===im in not continue");
reject(errorResult);
} else {
//LOGING THE RESPONSE BODY
log.info('body:', body);
var responseData = JSON.parse(body);
console.log("======RESPONSE=========DATA=====================");
console.log('error:', e);
console.log('statusCode:', r && r.statusCode);
console.log('body:', body);
console.log("====================================");
console.log(responseData);
resolve(responseData);
}
});
});
}
//INDEX.js
router.get("/example1", function (req, res) {
requestHandling.requestMethodGet('http://localhost:8083/getUserInfo/865c2c25-
d9e7-412d-a064-326bd66c9e9c', res).then((result) => {
console.log("===RESULT=====");
console.log(result);
}).catch((err) => {
console.log("===Error=====");
console.log(err);
});
});
you can use Promise or async/await
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.
dashboardRouter.route('/:Teachersubjects/:Class/:Salary')
.get(function(req,res)
{
function handleErr(err,redir)
{
if(redir){
res.end("err");
}
else{
res.writeHead(200, {"content-type": "text/plain"});
res.end('Error occured');
}
}
Verify.verifySchoolUser(req,res,function(err,schooluserId){
if(err){
res.redirect('/schoolusers/login');
return;
}
else{
SchoolUser.findOne({_id:schooluserId}).exec(function(err,schooluser){
if(err)
{
console.log("NOUSER school")
handleErr(err);
return;
}
else
{
if(schooluser.count<4){
console.log(req.params.Class);
vacancies.create(req.params,function(err,vacancy){
if(err){
console.log(err.message);
console.log(err.name);
console.log("create error");
for (field in err.errors) {
console.log(err.errors[field].message);
}
handleErr(err);
return;
}
console.log(vacancy);
schooluser.vacancies.push(vacancy._id);
schooluser.save(function(err){
if(err){
console.log(JSON.stringify(err));
handleErr(err);
}
teacherforms.find({}, function (err, teacherforms) {
if (err) throw err;
else {
var teacherforms = teacherforms;
console.log(teacherforms);
var arr=[];
for(i=0; i<teacherforms.length; i++ ) {
arr.push(teacherforms[i]._id);
console.log(arr);
}
teacherusers.find({checking:{$in:arr}}, function (err, teacherusers){
if (err) throw err;
else{
var data =[];
for(i=0; i<teacherusers.length; i++ ) {
var kdata={};
var str = "";
kdata.firstname = teacherusers[i].firstname;
kdata.profilepic= teacherusers[i].profilepic;
kdata.experience= teacherforms[i].Teachingexperience;
var len= teacherforms[i].Qualifications.length;
console.log(teacherforms[i].Qualifications);
for(j=len-1;j>=0;j--){
if(j==0){
str = str + teacherforms[i].Qualifications[j];
}
else{
str=str + teacherforms[i].Qualifications[j] + ", ";
}
}
kdata.qualifications = str;
data.push(kdata);
}
data.push(vacancy.Class);
//data.push(vacancy.Qualification);
data.push(vacancy.Teachersubjects);
console.log(data);
res.render('../views/dashboard/dashboard_resumes.ejs',{
sdata:data
});
}
});
}
})
});
})
}
else {
res.send("Limit Exceeded");
}
}
});
}
});
});
I want to save a object firstly in MongoDB at get request and then render a page in ejs with a new object.But I am getting a error 500(Internal Server Error),so can we save a object and render the ejs page with new object at same end point?
P.S- The code below is the crucial part of the code and there is no syntax error and schooluser(object) is passed from the upper part of the code.
dashboardRouter.route('/:Teachersubjects/:Class/:Salary')
.get(function(req, res) {
vacancies.create(req.params, function(err, vacancy) {
if (err) {
console.log(err.message);
console.log(err.name);
console.log("create error");
for (field in err.errors) {
console.log(err.errors[field].message);
}
handleErr(err);
return;
}
schooluser.vacancies.push(vacancy._id);
schooluser.save(function(err) {
if (err) {
handleErr(err);
} else {
res.render('../views/dashboard/dashboard_resumes.ejs', {
sdata: data
});
}
});
});
});
There are multiple issues with your route handler. First, whenever an error occurs you run this through your handleErr() function, but you never do anything with res in these cases. This means that the request is never resolved and eventually times out on the client side.
When an error occurs, you should respond with an error code. For instance:
res.status(400).send('Something went wrong');
When you actually do send a response and render the template, you're applying a variable called data. However, this variable doesn't seem to be declared anywhere in your code. Maybe you left out that code, but if that variable is indeed undeclared, it throws a ReferenceError which is caught by the routing framework which in turn responds with a 500 Internal Server Error. So this is probably the source of your issue.
Any uncaught errors thrown by vacancies.create() or schooluser.save() would have the same effect.
Hello I have a post event that takes in key value and maps it to a sproc. This part works very well. However, for some reason I cannot return the data response as JSON.
It says the return type is "octet stream" even though I'm setting it to application/json.
I'm a little new to REST, so if I'm doing something incorrectly, please let me know.
server.post({ path: PATH + '/data.json', version: '1.0' }, genericData);
function genericData(req, res, next) {
if (req.params.data != null){
var sp_code_name = config.get('data:' + req.params.data);
var connection = new sql.Connection(conn_str, function(err) {
// ... error checks
if(err) {
return console.log("Could not connect to sql: ", err);
connection.close();
}
});
var request = new sql.Request(connection);
console.log(sp_code_name);
request.execute(sp_code_name, function (err, recordset, returnValue) {
if (err) {
connection.close();
return console.log("Is this a good query or the right table?: ", err);
}
//if (recordset && returnValue == 0) {
res.setHeader('Access-Control-Allow-Origin','*');
res.setHeader('content-type', 'application/json');
res.send(200, recordset[0]);
console.log(recordset[0]);
// return next();
// }
// return next();
connection.close();
});
}
res.setHeader('content-type', 'application/text');
res.send(200, "Something is wrong with the stream.");
}
You need to wrap your error response in an else clause:
if (req.params.data != null){
...
} else {
res.setHeader('content-type', 'application/text');
res.send(200, "Something is wrong with the stream.");
}
Without the else clause, it's getting called on every request before your request.execute callback is called. That's setting your content-type to application/text instead of application/json as you're expecting.
When posting data from jquery to a node.js process sometimes it work, sometimes it doesn't. It depends on how I structure the code. This way it works:
http.createServer(router).listen(5000, '127.0.0.1');
console.log('Server running at http://127.0.0.1:5000/');
function router(req, res){
var page = url.parse(req.url, true);
switch(page.pathname){
case '/new-task': tasks.postNewTask(req, res); break;
}
}
"tasks" is a module I load. Inside there's postNewTask:
function postNewTask(req, res){
core.postRequest(req, res, function () {
// lots of stuff inside
})
}
postRequest is a function I "borrowed" here from Stackoverflow. It's defined as:
function postRequest(request, response, callback) {
var queryData = "";
if(typeof callback !== 'function') return null;
if(request.method == 'POST') {
console.log("it's post");
request.on('data', function(data) {
console.log("it's data");
queryData += data;
if(queryData.length > 1e6) {
console("too much stuff");
queryData = "";
response.writeHead(413, {'Content-Type': 'text/plain'});
request.connection.destroy();
}
});
request.on('end', function() {
console.log("it's end");
response.post = querystring.parse(queryData);
callback();
});
} else {
console.log("no post");
response.writeHead(405, {'Content-Type': 'text/plain'});
response.end();
}
}
This works perfectly and and the code inside tasks.postNewTask runs. However when I change the router to this:
function router(req, res){
var page = url.parse(req.url, true);
var session = core.getCookies(req).s;
if (page.pathname == '/login') {
core.postLogin(req, res); return; }
database.query('SELECT * from Members WHERE Session = ?;', [session], function(err, rows, fields) {
if (err) throw err;
if (rows.length>0) {
switch(page.pathname){
case '/new-task': tasks.postNewTask(req, res); break;
}
} else {
res.writeHead(200, "OK", {'Content-Type': 'application/json'});
res.end(JSON.stringify('login'));
};
});
}
then postRequest no longer works. It will only print "it's post" and that's it. It never prints data or that it reaches end. It also seems to never return to the client as I get a timeout on the browser.
The problem here is that "data" and "end" events in postRequest are never called, when the only thing I changed was to wrap the database call around the switch statement.
Thanks!
You have 3 console outputs in postRequest
it's post
it's data
it's end
First is fired regardless because the if condition just checks for request type, rest two are done when request gets data and end signals, asynchronously. So if postNewTask returns or sends response to the request then it may not reach that part. Check what you are doing in // lots of stuff inside
Also on searching for your mysql documentation https://npmjs.org/package/mysql I found :
You MUST NOT provide a callback to the query() method when streaming rows.
So check on that too.