I have a route that first need to query the database, then with the results, query another web service, then with that result render the page.
I have that flow worked out and am trying to figure out the error handling. Given that i talk to multiple service, I'm trying to massage the error before returning them to express.
Here is the structure of the code for the route:
Models.Episode.findById(request.params.episodeID)
.catch(function (error) {
throw (throwjs.notFound());
})
.then(function (episode) {
if (episode.getUser().id !== request.user.href) {
return next(throwjs.unauthorized("You do not have access to this podcast"));
}
return doSomeOtherAsyncStuff();
})
.then(function (queryResponse) {
renderPage();
})
.catch(function (error) {
next(error);
});
My problem is with the first catch. My goal in this catch is to repackage the error and stop the execution and send the error to express middleware.
With the way it is written above, the execution stops, but my express error handler are not called.
I tried rewriting the first catch as
.catch(function(error){
return next(error);
})
But that does not solve the issue. The only solution i found is to move the catch to the end. But then i lose context of the failure location.
Any clue as to what i'm doing wrong?
Thanks, olivier
I'd recommend taking a different approach so you don't have to rely on long running promise chains. With the following approach, you've decoupled your authorization and and validation to separate middleware, since they're not necessarily a concern of the actual episode handler itself. Plus this approach is more idiomatic to express.
An added bonus is that you're free to pass errors down to an error handler so you further decouple your errors from your route handlers.
function validateEpisode(req, res, next) {
Models.Episode
.findById(req.params.episodeID)
.then(function(episode) {
req.yourApp.episode = episode;
next() // everything's good
})
.catch(function(error) {
// would be better to pass error in next
// so you can have a general error handler
// do something with the actual error
next(throwjs.notFound());
});
}
function authUserByEpisode(req, res, next) {
if (req.yourApp.episode.getUser().id !== req.user.href) {
next(throwjs.unauthorized("You do not have access to this podcast"));
}
next(); // authorized
}
function episodeController(req, res) {
// do something with req.yourApp.episode
}
app.get('/episode/:id', validateEpisode, authUserByEpisode, episodeController)
Well after all, this is related to the throwjs framework I'm using and the fact that I'm using incorrectly
throw (throwjs.notFound());
should be
throw (new throwjs.notFound());
...
Related
In express I have a handler for a route ex:
router.get(`${api}/path/:params/entrypoint`, routeHandler);
In this example 'routeHandler' function has a lot of logic doing various things. I'd like to break 'routeHandler' into smaller methods to ease readability and testability. So instead of:
routeHandler(req, res) {
//many lines of code
}
We could have:
routeHandler(req, res) {
helperOne(req, res);
helperTwo(req, res);
}
helperOne(req, res) {
//do stuff
}
helper2(req, res) {
//do stuff
}
I am being told not to do this by a coworker who is pretty senior, but I do not understand why. Does anyone know of any issues that can arise by passing the response or request objects into helpers? I can not think of any and google isn't revealing any clear answer.
Thanks!
Does anyone know of any issues that can arise by passing the response or request objects into helpers?
Yes you may run into some problems when passing those parameters, especially res. For example you may res.send multiple times (one in each function) which will raise an exception.
Scenario
A more concrete example is this
routeHandler((req, res) => {
helperOne(req, res);
helperTwo(req, res);
});
Based on some conditions, I want to stop and return an error from helperOne and not go execute any code from helperTwo. My definitions of these functions are like this
helperOne = (req, res) => {
const dataPoint = req.body.dataPoint; // a number for example
if (number > 10) {
return res.send("This is not valid. Stopping here...");
} else {
console.log("All good! Continue..");
}
}
helperTwo = (req, res) => {
res.send("Response from helperTwo");
}
Then let's say I do have req.body.dataPoint = 10, and I'm now expecting my routeHandler to stop after the return res.send in the first block of my if statement in helperOne.
This will not work as expected though, because the return will concern only helperOne which is the returning function. In other terms it won't propagate to routeHandler.
In the end an exception will be raised because routeHandler will call helperTwo and try to send a response again.
Solution
Don't send req or res. Just pass the data you need and handle the reponse in your main handler
An even better alternative is to use Express middlewares. Since you have multiple "sequential" handlers, you can chain multiple middlewares, which is closer to the standard Express.JS way
One reason to avoid doing this is that you're tightly coupling your helper functions to routeHandler, and encouraging complexity in the helpers. If you break up your helper functions so they only have a single responsibility, it's likely you'll only need to pass in a subset of the request.
Why are you passing in res, Are you sending a response from inside the helpers? Without knowing the details of your routeHandler implementation, I would see if you could handle logic in the helpers, but have them each return a value and keep the response-sending in the main routeHandler function. Here's a simple example:
handleRoute('/users/:userID', (req, res) => {
const { userID } = req.params;
const idIsValid = validateUserID(userID);
if (!idIsValid) {
return res.status(400).send('Invalid user ID!');
}
...
});
I'm new to using node.js and right now I'm working on an API which queries mongodb.
The following function apiRequest needs to call two functions, each of which performs a seperate db query.The problem with the current function is that if one of the query has some sort of error, I wouldnt be able to catch it.
What is the best way to implement this so its properly error handled. Someone pointed me to the async library and mentioned that I had to do something with promises but I really cant figure it out. Ideally I wouldnt want to change the definition of dbQueryOne and dbQueryTwo since they are being used in other places aswell.
exports.apiRequest =function(req,res) {
dbQueryOne(req.body.inputA);
dbQueryTwo(req.body.inputA);
res.send('Moved For Further Action',200);
}
exports.apiRequest = function(req,res) {
dbFuncs = [dbQueryOne(req.body.inputA), dbQueryTwo(req.body.inputA)];
Promise.all(dbFuncs)
.then(result => {
res.send('Moved For Further Action',200);
})
.catch(err =>{
//catch err
});
}
You can use promise.all to run multiple queries and catch any error that has occurred in the catch block
AS We have Exception filter in asp.net MVC, do we have similar kind of functionality in node.js with express 4 also?
I have tried following articles but didn't find the desired solution.
http://www.nodewiz.biz/nodejs-error-handling-pattern/
I have also tried below on app.js
process.on('uncaughtException', function (err) {
console.log(err);
})
ref article: http://shapeshed.com/uncaught-exceptions-in-node/
Any help would be appreciable.
Errors might came from and caught in various locations thus it's recommended to handle errors in a centralized object that handles all types of errors. For example, error might occurs in the following places:
1.Express middleware in case of SYNC error in a web request
app.use(function (err, req, res, next) {
//call handler here
});
2.CRON jobs (scheduled tasks)
3.Your initialization script
4.Testing code
5.Uncaught error from somewhere
process.on('uncaughtException', function(error) {
errorManagement.handler.handleError(error);
if(!errorManagement.handler.isTrustedError(error))
process.exit(1)
});
6.Unhandled promise rejection
process.on('unhandledRejection', function(reason, p){
//call handler here
});
Then when you catch errors, pass them to a centralized error handler:
module.exports.handler = new errorHandler();
function errorHandler(){
this.handleError = function (error) {
return logger.logError(err).then(sendMailToAdminIfCritical).then(saveInOpsQueueIfCritical).then(determineIfOperationalError);
}
For more information read bullet 4' here (+ other best practices and more than 35 quotes and code examples)
In express, it's standard practice to have a catch all error handler attached.
A barebones error handler would look like
// Handle errors
app.use((err, req, res, next) => {
if (! err) {
return next();
}
res.status(500);
res.send('500: Internal server error');
});
Along with this, you will need to catch errors anywhere they can happen and pass them as a param in next(). This will make sure that the catch all handler catches the errors.
To add global exceptions handlers in node are events on process. Use process.on to catch them.
process.on('uncaughtException', (err) => {
console.log('whoops! there was an error');
});
Write a middleware to handle like below for all routes in express js
function asyncTryCatchMiddleware(handler){
return async (req,res,next) => {
try{
await handler(req,res);
} catch(e) {
next(e)
}
};
}
You can use the middleware like this:
router.get('/testapi',asyncTryCatchMiddleware(async (req,res)=>{
res.send();
}));
I'm trying to request the data from server using dojo jsonrest store. While requesting i'm catching the callback to do some stuff. For example
this.myStore.get(paramValue).then(lang.hitch(this, function (res) {
//do something like this.globalVal = res;
}, function (err) {
console.log(err);
//throw error
}));
But the above code only works when the request returns success, i.e. it dose enter in the first block of deferred on success return, but when some error occurred, it failed to reach in the error callback and hence i'm not able to catch the errors returned by server.
If i do the above code without using lang.hitch like this
this.myStore.get(paramValue).then(function (res) {
//do something like this.globalVal = res;
}, function (err) {
console.log(err);
//throw error
});
Then it works. i.e. it will now reach to the error callback as well and i can throw the appropriate error to user.
So why dose this happen, and if lang.hitch is not something that can be used with deferred then what to use?
Thanks
Hitch accepts two arguments, context and the function which is to be executed in the preceding context. At the moment you're using three, that won't work. You're trying to wrap two functions into the same hitch. You'll need to wrap them each in a separate hitch:
this.myStore.get(paramValue).then(
lang.hitch(this, function success (res) {
console.log('Success');
}),
lang.hitch(this, function error (err) {
console.log('Error');
})
);
Here's the setup in a module. See, esp., comments marked by ****:
exports.saveWall = function (req, res) {
var status;
mongoClient.connect(connectionString, function (err, db) {
if (err) { return console.dir(err); }
db.collection(pictureWallsCollectionName).insert(
{ _id: req.body.wallId, pictures: req.body.pictures },
function (err, res) {
db.close();
if (err) {
status = 500;
console.dir(err);
}
else {
status = 200;
//*****can't do this here, because res is out of scope!
res.status(status).send(http.STATUS_CODES[status])
console.log('Inserted into the ' + pictureWallsCollectionName + ' collection');
}
});
});
//*****can't do this yet because the above isn't done.
res.status(status).send(http.STATUS_CODES[status])
}
I basically want to call the line res.status(status).send(http.STATUS_CODES[status]) in my callback, but I can't because res.status is null at that point.
All I want to do is respond to a POST, but I am not getting anywhere.
Even though you solved your scope issue (which is awesome), nesting callbacks can get kind of tricky quickly (as you saw). A good way to deal with this is to use promises. The two main packages for promises are Q and Bluebird (with Bluebird being my favorite).
You can also use a package that has already promise-ified mongo calls for you, like promised-mongo
Once you have that all set up, it's just a matter of chaining .then for successive steps, and then sending your response when the promise is resolved.
For a specific example, check out this answer and see if that helps.
Ugh...
It turns out my issue was that "res" was defined both here:
exports.saveWall = function (req, res) {
...and here:
db.collection(pictureWallsCollectionName).insert(...,
function (err, res) {
...so it turns out I could call "res" all along, I was just trying to call the wrong "res" because it got redefined.
On a side note, f*** you, javascript!