DragoonHP DragoonHP - 4 months ago 7
Node.js Question

Stopping response if document isn't found

My script checks if an id exists inside the database. If it doesn't, it's supposed to stop the logic right there and then.

But what happens currently is instead of returning the "The provided Project Id does not exist in our database.", it returns "Please send all the required details.".
(Probably because the first return takes us out of the function)

var projectExists = function(pId, callback) {
ProjectsData.count( {project_id: pId}, function(err, doc) {

if (err) {
throw err;
}
callback(doc);
});
};

// Create a new Game ID.
v1.post("/", function(req, res, next) {

if ( !("project_id" in req.body) ) {
return res.send("You need to provide Project ID");
}

// Check if the Project ID is in the file.
// Problematic bit
projectExists( req.body.project_id, function(c) {
if ( c == 0 ) {
return res.send("The provided Project Id does not exist in our database.");
}
});

var gameDataObj = req.body;

GameData.addGameId(gameDataObj, function (err, doc) {
if (err) {
if (err.name == "ValidationError") {
return res.send("Please send all the required details.");
}
throw err;
};

res.json(doc);
})
});


What am I doing wrong? Is there any better way of doing this?




And a follow up question; in the current iteration, if the id is wrong there is also this error:

Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header (G:\node\vnlytics\node_modules\express\lib\response.js:719:10)
at ServerResponse.send (G:\node\vnlytics\node_modules\express\lib\response.js:164:12)
at G:\node\vnlytics\controllers\v1\game.data.js:35:17
at G:\node\vnlytics\controllers\v1\game.data.js:20:9
at Query.<anonymous> (G:\node\vnlytics\node_modules\mongoose\lib\model.js:3331:16)
at G:\node\vnlytics\node_modules\kareem\index.js:259:21
at G:\node\vnlytics\node_modules\kareem\index.js:127:16
at nextTickCallbackWith0Args (node.js:420:9)
at process._tickCallback (node.js:349:13)


It's probably because we are sending two response but what's weird is that checking res.headersSent until the last moment returns false.

Answer

As I said in my comment, you need to properly sequence your async operations so you don't start the next one until you know the result of the previous one and have processed that. You can do that like this:

// Create a new Game ID.
v1.post("/", function(req, res, next) {

    if ( !("project_id" in req.body) ) {
        return res.send("You need to provide Project ID");
    }

    // Check if the Project ID is in the file.
    // Problematic bit
    projectExists( req.body.project_id, function(c) {
        if ( c == 0 ) {
            return res.send("The provided Project Id does not exist in our database.");
        } else {
            var gameDataObj = req.body;

            GameData.addGameId(gameDataObj, function (err, doc) {
                if (err) {
                    if (err.name == "ValidationError") {
                        return res.send("Please send all the required details.");
                    }
                    throw err;
                };

                res.json(doc);
            })
        }
    });

});

P.S. You should replace the throw err with proper error handling. You need to actually send an error response here. The throw won't do anything useful other than stop processing when a response has never been sent.

Comments