Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js res.send VS res.end VS return res.end

I have the following code that has a syntax error in the mongodb findAndUpdateOne update query.

router.post('/buylicense', isLoggedIn, function(req, res) {
    if (!req.body.cid) {
        return res.send('failed');
    }
    Company.findOne({
        ownedBy: req.user.local.username,
        _id: req.body.cid
    }, function(err, result) {
        if (err) {
            return res.send('failed');
        }
        if (result.license) {
            return res.send('valid');
        } else {
            Company.findOneAndUpdate({
                ownedBy: req.user.local.username,
                _id: req.body.cid
            }, {
                license: true,
                licenseExpireDate: {
                    $add: ["$date", 3 * 24 * 60 * 60000] // bad code, a problem for another day
                }
            }, function(err) {
                if (err) {
                  console.log(err);
                  return res.end('failed'); // Code should stop here.
                }
                console.log('got here');
                return res.send('success');
            });
        }
    });
    console.log('How did I get here?');
    res.send('failed');
});

My question is why is the code reaching the last part of the code:

 console.log('How did I get here?');
 res.send('failed');

If I use anything other than return res.end the code reaches the end and crashes my app. Simply doing res.end does not work, neither does return res.send. Should not return or at least res.end be enough to actually stop the code from reaching the end?

Error displayed if I don't stop the error the right way, probably not relevant but here it is:

How did I get here?
{ CastError: Cast to date failed for value "[object Object]" at path "licenseExpireDate"
    at MongooseError.CastError (/media/node_modules/mongoose/lib/error/cast.js:19:11)
    at SchemaDate.cast (/media/node_modules/mongoose/lib/schema/date.js:242:9)
    at SchemaDate.castForQuery (/media/node_modules/mongoose/lib/schema/date.js:276:17)
    at Query._castUpdateVal (/media/node_modules/mongoose/lib/query.js:2477:17)
    at Query._walkUpdatePath (/media/node_modules/mongoose/lib/query.js:2372:25)
    at Query._castUpdate (/media/node_modules/mongoose/lib/query.js:2296:23)
    at castDoc (/media/node_modules/mongoose/lib/query.js:2500:18)
    at Query._findAndModify (/media/node_modules/mongoose/lib/query.js:1755:17)
    at Query._findOneAndUpdate (/media/node_modules/mongoose/lib/query.js:1622:8)
    at /media/node_modules/kareem/index.js:156:8
    at args (/media/node_modules/kareem/index.js:71:20)
    at Query.<anonymous> (/media/node_modules/mongoose/lib/schema.js:728:7)
    at next (/media/node_modules/kareem/index.js:82:14)
    at Kareem.execPre (/media/node_modules/kareem/index.js:99:3)
    at Kareem.wrap (/media/node_modules/kareem/index.js:146:8)
    at Query._findOneAndUpdate (/media/node_modules/kareem/index.js:188:11)
  message: 'Cast to date failed for value "[object Object]" at path "licenseExpireDate"',
  name: 'CastError',
  kind: 'date',
  value: { '$add': [ '$date', 259200000 ] },
  path: 'licenseExpireDate',
  reason: undefined }
got here
_http_outgoing.js:346
    throw new Error('Can\'t set headers after they are sent.');
    ^

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
    at ServerResponse.header (/media/node_modules/express/lib/response.js:718:10)
    at ServerResponse.send (/media/node_modules/express/lib/response.js:163:12)
    at /media/sf_vShared/xyz/app/modalRoutes.js:461:28
    at /media/node_modules/kareem/index.js:160:11
    at Query._findAndModify (/media/node_modules/mongoose/lib/query.js:1767:14)
    at Query._findOneAndUpdate (/media/node_modules/mongoose/lib/query.js:1622:8)
    at /media/node_modules/kareem/index.js:156:8
    at args (/media/node_modules/kareem/index.js:71:20)
    at Query.<anonymous> (/media/node_modules/mongoose/lib/schema.js:728:7)
    at next (/media/node_modules/kareem/index.js:82:14)
    at Kareem.execPre (/media/node_modules/kareem/index.js:99:3)
    at Kareem.wrap (/media/node_modules/kareem/index.js:146:8)
    at Query._findOneAndUpdate (/media/node_modules/kareem/index.js:188:11)
    at Query.findOneAndUpdate (/media/node_modules/mongoose/lib/query.js:1611:15)
    at Function.Model.findOneAndUpdate (/media/node_modules/mongoose/lib/model.js:1491:13)
[nodemon] app crashed - waiting for file changes before starting...
like image 424
Trax Avatar asked Jul 06 '16 09:07

Trax


1 Answers

First let's see what is the difference between three ExpressJS functions

res.end: comes from NodeJS core. In Express JS if you need to end request in a quick way and do not need to send any data then you can use this function

res.send: Sends data and end the request

res.json Sends data in JSON format and ends the request.

My question is why is the code reaching the last part of the code:?

I hope you know that JavaScript is asynchronous language. All database calls to MongoDB using Mongoose is asynchronous. So Compnay.findOne is an asynchronous function call and It stays in event loop until database read operation is not finished. As asynchronous behavior of JS, JS Main thread execution won't wait for the DB function result to return ( no-blocking) and reach the last lines and as your req ends with calling res.end("failed") But when DB read operation finished returns data then you again calling res.send and you ended with Error: Can't set headers after they are sent.

Hope this helps :)

like image 94
Nur Rony Avatar answered Oct 21 '22 08:10

Nur Rony