404 Response not being set on error | Node.JS & MongoDB - node.js

I'm facing a issue in a Node.JS application I'm writing.
I'm trying to get a JSON string as POST and saving that JSON to mongodb.
Inserts are working fine but I'm not able to handle error scenarios from snippet which is responsible for interacting with mongodb.
E.g. in the snippet below, I'm getting expected 404 response at "Error" comments #1, 3, 4 in server.js, when respective conditions are fulfilled, but 404 response at comment #2 is not coming.
However, I am getting errors printed in console from insertintomongo.js at comment #5 and 6 and that error object is also successfully sent back to server.js.
I'm not able to figure out why response is not set to 404 even when I know that code has gone into correct if condition (as shown by console output).
Snippet of JS handling requests (server.js)
var imongo=require("./insertintomongo.js");
http.createServer(function (request, response) {
if (uri == "/ssd/add" && request.method == 'POST') {
console.log(request.method + " to " + request.url);
var fullBody = '';
request.on('data', function(chunk) {
fullBody += chunk.toString();
});
request.on('end', function() {
try {
JSON.parse(fullBody);
} catch (e) {
// Error 1
console.log('Invalid JSON. Error message: ' +e);
response.writeHead(404, "Input data is not in JSON format" , {'Content-Type': 'text/html'});
response.end('<html><head><title>Input data is not in JSON format</title></head><body><h1>Input data is not in JSON format</h1></body></html>');
}
var inputJSON = JSON.parse(fullBody);
if ( inputJSON.deployment_id != undefined ){
inputJSON._id=inputJSON.deployment_id;
imongo(inputJSON,function(err){
if(err){
// Error 2
console.log('Error 2: ' + err);
response.writeHead(404, "Error saving input data" , {'Content-Type': 'text/html'});
response.end('Error inside callback');
} else {
console.log("All good");
};
});
} else {
// Error 3
console.log("Incorrect json provided");
response.writeHead(404, "Incorrect json provided", {'Content-Type': 'text/html'});
response.end('<html><head><title>Incorrect json provided</title></head><body><h1>Incorrect json provided.</h1><h3>"deployment_id" field is missing.</h3></body></html>');
};
// OK 1
response.writeHead(200, "OK", {'Content-Type': 'text/html'});
response.end();
});
} else {
// Error 4
response.writeHead(405, "Method not supported", {'Content-Type': 'text/html'});
response.end('<html><head><title>Method not supported</title></head><body><h1>Method not supported.</h1></body></html>');
}
}).listen(8081);
insertintomongo.js which is included in above JS
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var url = 'mongodb://localhost:27017/mytest';
function saveToMongo(input,cb){
MongoClient.connect(url, function (err, db) {
if (err) {
// Error 5
console.log('Unable to connect to the mongoDB server. Error:', err);
cb(err);
} else {
var collection = db.collection('users');
collection.insert([input], function (err, result) {
if (err) {
// Error 6
cb(err);
} else {
console.log('Inserted '+ result.result.ok+ ' documents into collection. The documents inserted with "_id" are:' + JSON.stringify(result.ops));
cb(null);
}
db.close();
});
}
});
};
module.exports=saveToMongo;
Here's Console output
Server runing at 8081
POST to /ssd/add
// This is coming from inserttomongo.js
Error 5: Unable to connect to the mongoDB server. Error: { [MongoError: connect ECONNREFUSED 127.0.0.1:27018]
name: 'MongoError',
message: 'connect ECONNREFUSED 127.0.0.1:27018' }
// This is coming from server.js
Error 2: MongoError: connect ECONNREFUSED 127.0.0.1:27018

OK, figured out the issue. I had to remove these lines from previous place and put it in else condition of "Error 2" comment.
// OK 1
response.writeHead(200, "OK", {'Content-Type': 'text/html'});
response.end();
This is because call to imongo is async and response was being set 200 even before the imongo was finished.
Very basic mistake :(

Related

Why is this express route returning a 200 status code when the code says to return a 500?

I have this route that is expcted to return a 500 status code.
/* Return all the users id */
router.post('/user/list', async function (req, res, next) {
const data = await scanAll(req.body.port, req.body.ip);
console.log("data ", data) //data 500
if (data === 500) {
res.json({
error: "Error, server connection refused"
}).status(500);
}
else if (data.length === 0) {
res.json(data).status(204)
} else {
res.json(data).status(200);
}
})
It scans a redis server and returns the data.
Well my front end received the json of the error. But receives the 200 status code. Same goes for postman
How is that possible?
According to Express API: https://expressjs.com/en/4x/api.html#res.status
You need to call status before calling json or send
res.status(400).send('Bad Request')
res.status(500).json({ error: "Error, server connection refused" })
Refer examples from,
https://expressjs.com/en/4x/api.html#res.send
https://expressjs.com/en/4x/api.html#res.json
https://expressjs.com/en/4x/api.html#res.status
So change the above snippet to,
/* Return all the users id */
router.post('/user/list', async function (req, res, next) {
const data = await scanAll(req.body.port, req.body.ip);
console.log("data ", data) //data 500
if (data === 500) {
res.status(500).json({
error: "Error, server connection refused"
});
}
else if (data.length === 0) {
res.status(204).json(data);
} else {
res.status(200).json(data);
}
})

Node.js Http Write after end

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

Node.js type error first argument must be a string or buffer

I have written a small code in node.js to insert a document in MongoDB collection. But as I make a request for profile route I get the error I mentioned in the title. I can't figure out which line is causing the problem, maybe it is the one after insertOne method. The code is:
http
.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/html" });
var url = req.url;
if (url == "/") {
res.end("<h1>Basic route</h1>");
} else if (url == "/profile") {
mydb
.collection("record")
.insertOne({ username: "vipul", password: "vipul1234" }, (err, result) => {
if (err) res.end(err);
else res.end("inserted successfully");
});
} else if (url == "/about") {
res.end("<h1>About Us Page</h1>");
} else {
let date = Date();
res.end("<h1>Incorrect URL</h1><h2>", date, "</h2>");
}
})
.listen(3000, () => {
console.log("Server listening at port 3000");
});
Please guide me through. I am a beginner to Node!
About this:
if (err)
res.end(err);
else
res.end("inserted successfully");
res.end does not accept the error itself. You have to pass it a string or a buffer.
(See more here: https://nodejs.org/api/http.html#http_response_end_data_encoding_callback)
You can try this:
if (err)
res.end(err.message);
else
res.end("inserted successfully");

Error handling in node js backend

I'm using a node.js backend and I got some problems with the error handling.
In the backend I use express for routing. I get a ajax post from the frontend with a array and some data in it. This data should be saved in the database. If there is an error by adding the data to the DB I get the error message in the backend but I also want so send a message to the frontend. I was try and erroring around but in the frontend I always get 'succesfull'.
This is my code till now.
Backend:
router.post('/tagging', function(req, res) {
var taggedData = req.body;
var actions = taggedData.map(element => {
addTaggedData.addTaggedData(element)
.then(function(result) {
return result;
})
.catch(function(err) {
if (err.code == "ER_NO_SUCH_TABLE") {
console.log("Tagged data contains unknown project name");
res.send("ER_NO_SUCH_TABLE");
} else {
res.send(err);
}
})
});
Promise.all(actions)
.then(
res.send("Successful")
)
.catch(function(err) {
if (err.code == "ER_NO_SUCH_TABLE") {
console.log("Tagged data contains unknown project name");
res.send("ER_NO_SUCH_TABLE");
} else {
res.send(err);
}
});
})
Frontend ajax call:
function postTaggedData(taggedData) {
$.ajax({
url: server_connection.url + '/tagging',
type: 'POST',
encoding: "UTF-8",
contentType: 'application/json',
data: JSON.stringify(taggedData),
success: function(data) {
if (data === "Successful") {
console.log("Tagged Data successfully send to server");
}else if(data == "ER_NO_SUCH_TABLE"){
alert("Unknown project");
} else {
alert(data);
}
},
error: function(xhr, status, error) {
if(error == "Internal Server Error"){
alert("There is an error with the server");
}else if(error == "ER_NO_SUCH_TABLE"){
alert("Unknown project");
}else{
alert("There was an error while sending the Tagged Data to the server");
console.log(xhr, "Status: ", status, error);
}
}
})
}
Even though you're sending error as a response, express doesn't know it's an error, so it sends it with status code 200 which means OK, so front-end thinks, response was successful.
Try setting the non-ok status and then sending an error like this: res.status(404).send(err). Where 404 is a status code for "Not Found"
You can find more about status codes here
You can find more about express error handling here

Node.js http-proxy: Error response not sent to client

I'm using proxy.web to forward client requests.
When destination server is up, my code works as expected.
When destination server is down, ECONNREFUSED error is catch and printed to console.log. I would like to send that error back to the client, and tried using the sample provided here. Unfortunately, the error response does not arrive to the client (tried both chrome and firefox). Please find below code. Why does the response not sent to the client ?
var proxyServer = http.createServer(function(req, res) {
if(req.path === 'forbidden') {
return res.end('nope');
}
var url_parts = url.parse(req.url);
var extname = path.extname(url_parts.pathname);
if (extname || url_parts.pathname.length <= 1){
proxy.web(req, res, {
target: 'http://localhost:'+config.fileServer.port
});
}
else{
proxy.web(req, res, {
target: config.recognitionServer.url
}, function(e) {
console.log(e.message);
if (!res.headersSent) {
res.writeHead(500, { 'content-type': 'application/json' });
}
res.end(JSON.stringify({ error: 'proxy_error',
reason: e.message
}));
});
}
}).listen(config.proxyServer.port, function () {
console.log('Proxy server is listening on port '
+ config.proxyServer.port);
});
A good approach is this:
return res.status(500).send({
error: true,
message: 'your-error-message'
});
Your code rewritten:
proxy.web(req, res, {
target: config.recognitionServer.url
}, function (e) {
console.log(e.message);
return res.status(500).send({
error: true,
message: e.message
});
});
Problem was solved on client side :)
Client code is JS using XMLHttpRequest (tested on FF and Chrome). The error response arrives to "onload" event handler, not to "onerror".
The "onload" handler function needs to check response status. If error status (500), continue with error handler.

Resources