A promise was created in a route but not returned from - node.js

i tried to find a solution for this warning i get, but none of the suggested approaches worked for me. I don't want to disable this warning, because i believe this warning is there for a reason, but i can't figure out whats the real deal here.
I have the following route defined on my node.js server running express:
// GET all items
router.get('', helpers.loginRequired, function(req, res) {
debug("Get all items");
return knex.select('*').from('routes')
.then((routes) => {
res.send(routes);
return null;
})
.catch((err) => {
debug("error getting routes");
res.send({ error: "Fehler beim Laden" });
return null;
});
});
My Middleware loginRequired does not use any promise at all
function loginRequired(req, res, next) {
if (!req.user) {
req.flash('loginMessage', 'Du musst eingeloggt sein!');
req.session.redirectTo = req.path;
return res.redirect('/');
} else {
return next();
}
}
I use knex for accessing my database, which creates promises.
And everytime i hit the route, i get the following warning:
(node:10568) Warning: a promise was created in a handler but was not returned fr
om it, see *link*
at Function.Promise.attempt.Promise.try (C:\Users\qxr1088\Desktop\Privat\GPS
\bibis-tracker\node_modules\bluebird\js\release\method.js:29:9)
As you can see i tried to add the "return null;" statements as suggested by bluebird, but this does not fix the problem.

Related

same base url with different functionalities nodejs

app.get('/api/v3/app/events', async function (req, res){
try {
let unique_id=req.query.id
console.log(unique_id)
database.collection('event').findOne(ObjectId(unique_id),function(err,data){
if(err){
res.json({error:"no data found with specified id"})
}
console.log(data)
res.json(data)}
)
} catch (error) {
console.log("internal error")
res.json({error:error})
}
})
app.get('/api/v3/app/events', function(req,res) {
try {
let limit=parseInt(req.query.limit)
let page =parseInt(req.query.page)
console.log(database.collection('event').find().sort({$natural: -1}).limit(limit).skip(page-1).toArray((err, result) => {
console.log(result);
})
)
} catch (error) {
console.log(error)
return res.json({error:"internal error "})
}
})
I have to perform these functionalities with same base url i.e '/api/v3/app/events'.
Please help . I am successful as I change the names of endpoints, but keeping them same , I gets null and undefined on the console
I'm not sure why do you need both to use same URL, but you have two choices either use a single endpoint with both of the logics. The other option would be to use the next middleware based on the id query param like this:
app.get('/api/v3/app/events', async function (req, res, next){
if (!req.query.id) {
next();
return;
}
// Rest of your endpoint logic
}
Each endpoint in Express is considered as middleware. This means that response won't be sent back, but calling the next() middleware instead and allow other middlewares to be executed. You can use same if or modify it based on your login.

promises - unhandled rejection hangs request

I'm developing a backend app in Node.js and I came across with following problem: When developer call promise function like below:
mainRouter.get("/xD", async (req, res) => {
res.send(await this.fooService.foo());
});
there is possibility that this.fooService.foo() function will fail (promise rejection) and the end user will get request timeout.
I want to be sure that developer mistake will not cause UnhandledPromiseRejectionWarning (and finally timeout error). The question is how to configure app to log errors and return status 500 to user when UnhandleRejection occurs.
What I tried:
mainRouter.get("/xD", async (req, res) => {
try {
res.send(await this.fooService.foo());
} catch (err) {
res.status(500).send("error");
}
});
Above code will do the thing but it requiers from developer to write above code in every route, so it's not quite a clean solution.
I also tried to use error middleware:
mainRouter.use((err:any, req, res, next) => {
console.log(err);
res.status(500).send("Error");
});
but it doesn't catch PromiseRejection
Finally I created middleware which registers function handler for unhandledRecejtion event:
mainRouter.use((req, res, next) => {
process.on('unhandledRejection', (reason, p) => {
console.log(reason);
res.status(500).send("Error");
});
next();
});
I'm not sure how process events works in node.js but I'm afraid that the code above will cause problems for scenario:
First request generates unhandled promise rejection
The newest request which registered handler last, will return to user status 500.
Why not just provide a wrapper function that everyone could use
async function wrapAsync(res, asyncFn) {
try {
res.send(await asyncFn());
} catch (err) {
res.status(500).send("error");
}
}
where asyncFn is a function that returns a promise
Then other developers can simply use it this way
mainRouter.get("/xD", async (req, res) => await wrapAsync(res, this.fooService.foo));
It may also be possible to overwrite mainRouter.get and provide an even shorter abstraction

Sails js beforeCreate next() callback

I am using sails js for my web application. I have to change the default behaviour of beforeCreate. First look at the code:
beforeCreate: function(values, next) {
//ParamsCheck is my service and 'check' is method which will validate the
//parameters and if any invalid parameter then error will be thrown, otherwise
//no error will be thrown
ParamsCheck.check(values)
.then(() => {
// All Params are valid and no error
next();
})
.catch((err) => {
//Some errors in params, and error is thrown
next(err);
});
}
So, the problem is if there is any error, then next method is automatically redirecting to serverError with error code 500, while I want to redirect it with my custom response(eg : badRequest , err code 400). How to achieve this?
You are performing some kind of validation in beforeCreate. However this is not the correct place for validation.
A better approach is to use custom validation rules as described here http://sailsjs.org/documentation/concepts/models-and-orm/validations#?custom-validation-rules or create a policy to handle the validation.
I like to use policies:
module.exports = function(req, res, next) {
var values = req.body;
ParamsCheck.check(values).then(() => {
return next();
}).catch((err) => {
return res.send(422); // entity could not be processed
});
};

Express.js - display a custom 404 page when a record is not found in MongoDB

I am using node-mongodb-native driver. I tried
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!result) throw new Error('Record not found!');
});
But the error is caught by mongodb driver and the express server is terminated.
What's the correct way for this case?
=== Edit===
I have the code below in app.js
app.configure('development', function() {
app.use(express.errorHandler({dumpExceptions: true, showStack: true}));
});
app.configure('production', function() {
app.use(express.errorHandler());
});
Related code in node_modules/mongodb/lib/mongodb/connection/server.js
connectionPool.on("message", function(message) {
try {
......
} catch (err) {
// Throw error in next tick
process.nextTick(function() {
throw err; // <-- here throws an uncaught error
})
}
});
The correct use is not to throw an error, but to pass it to next function. First you define the error handler:
app.error(function (err, req, res, next) {
res.render('error_page.jade');
})
(What's this talk about error being depracated? I don't know anything about that. But even if then you can just use use. The mechanism is still the same.).
Now in your route you pass the error to the handler like this:
function handler(req, res, next) {
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!result) {
var myerr = new Error('Record not found!');
return next(myerr); // <---- pass it, not throw it
}
res.render('results.jade', { results: result });
});
};
Make sure that no other code (related to the response) is fired after next(myerr); (that's why I used return there).
Side note: Errors thrown in asynchronous operations are not handled well by Express (well, actually they somewhat are, but that's not what you need). This may crash your app. The only way to capture them is by using
process.on('uncaughtException', function(err) {
// handle it here, log or something
});
but this is a global exception handler, i.e. you cannot use it to send the response to the user.
I'm guessing that the error is not caught. Are you using an Express error handler? Something like:
app.error(function (err, req, res, next) {
res.render('error-page', {
status: 404
});
More on error handling in Express: http://expressjs.com/guide.html#error-handling
In terms of checking for errors off mongodb, use '!error' for success as opposed to '!result' for errors.
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!error) {
// do good stuff;
} else {
throw new Error('Record not found!');
}
});
As for the custom 404, I've yet to do that in node and express, but I would imagine it would involve "app.router".

Handle jade errors in res.render()

I have a working node.js / express based server and am using jade for templating. Usually there is no problem but a couple of times every day I get an error message when requsting any page. The error is 'failed to locate view'. I don't know why i get this error since it worked fine just minutes before.
The question however is how I can force a crash on this event, for example:
res.render('index.jade', {info: 'msg'}, function(error, ok) {
if (error)
throw new Error('');
// Proceed with response
};
How would I do this? And how would I proceed with the response?
thank you.
You can add an error handling middleware.
app.use(function handleJadeErrors(err, req, res, next) {
// identify the errors you care about
if (err.message === 'failed to locate view') {
// do something sensible, such as logging and then crashing
// or returning something more useful to the client
} else {
// just pass it on to other error middleware
next(err);
}
});
Try this:
app.use(function (req, res, next) {
fs.exists(__dirname + '/views/' + req.url.substring(1) + '.jade', function (exists) {
if(!exists) {
console.log(err);
return next();
}
res.render(req.url.substring(1), { title: "No Controller", user: req.session.user });
}
});

Resources