Custom Error handling in Express submodules (e.g. in Service Layer) - node.js

I know about the Express documentation regarding Error handling, namely using next() to handle errors in async functions or throw to handle errors in sync functions. Throwing those from my route handler works fine, errors get passed to my custom errorHandler that I inserted via app.use().
However, what I never found in any documentation is, how would I best handle errors in an async function (e.g. in my Service Layer) or class that is called by a Route handler. Do I pass next() to that function? I really don't want to do that, as I want to keep all Express specific functions separate from my other application logic.
class someClassThatIsUsedInMyRouteHandler {
async create() {
throw new CustomError("some message", 401);
}
}

Oh man, tried a few things and in the end the problem was a type (error instead of err in my errorHandler). Doing next(error) in my controller works :)

Related

Best practices for handling uncaught Node exceptions with Express.js

I am writing a website with express and I found out that an uncaught exception would bring down the whole server(at least in debug mode).
Of course I could wrap every handler with (...).catch(err) and pass error with next(err), but that is just bad practice and wouldn't solve the problem (that the server goes down on uncaught error).
Before express I only had experience with Laravel and Laravel handles uncaught errors gracefully by sending a 500 to the user, unlike express.
Any thoughts? Perhaps this is easily googleable and I am being dumb asking this, but so far the best approach I found is catch every error manually (which is bad practice IMO, as it leaves possibility of server going down on uncaught exception)
If you switch to promises, you can write a single wrapper function that catches every error and calls next(err) for you, or use this package:
https://www.npmjs.com/package/express-async-handler
Otherwise, you should catch every asynchronous error.
Express is old and was written in a time before promises. There's some nicer frameworks out there these days that have better default behavior.
Express already catches synchronous exceptions for you and already calls next(err). All you need is an Express error handler defined.
Here's the simplest example:
app.use((err, req, res, next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
});
Express will not catch asynchronous exceptions or promise rejections for you automatically. To catch promise-rejections, you will have to do some sort of wrapper for all route handlers. There are a variety of ways to implement this wrapper. I've written a bit of a patch for Express that I sometimes use in my apps that automatically handles promise rejections in route handlers if they return a promise or if they are async and an await sees a rejected promise. It's unfortunate that Express is not being updated to handle this type of thing.
Asynchronous (callback-based) errors must be handled inside the callback since there's no universal way to propagate that error anywhere (this is why promise rejections are a better way to code).

Node.js & Express - Are Error objects ever created and passed to middleware without first being declared inside route?

Environment: Node.js, Express
The pattern below will forward all synchronous and asynchronous Error objects to my error handling middleware.
app.get('/', wrapAsync(async function(req, res, next) {
// synchronous error
throw new Error('oops');
// asynchronous error
//next( new Error('oops I did it again');
res.send('hello world');
}));
function wrapAsync(fn) {
return function(req, res, next) {
fn(req, res, next).catch(next);
};
}
app.use( function(error, req, res, next) {
res.send(error);
});
However what if an unexpected error occurs in part of my code where I didn't set up an Error object? Will node.js or Express detect that an error occurred in my route, create an Error object and forward it to my middleware through the wrapAsync wrapper function? This is hard for me to wrap my mind around because I'm not sure how to test for something unexpected.
Is there a pattern that ensures that all possible errors that occur in a route are forwarded to the error handling middleware without crashing the server?
However what if an unexpected error occurs in part of my code where I didn't set up an Error object?
If something throws besides your own code (a programming error or unexpected exception), than whatever threw will have created its own exception. It is convention, but not entirely required that you throw Error objects. Custom code could throw a string or its own object if it wanted to, though that is not the common convention.
An interpreter-generated exception (such as a TypeError) will always throw some type of Error object.
Will node.js or Express detect that an error occurred in my route, create an Error object and forward it to my middleware through the wrapAsync wrapper function?
That's not really the right way to think of it. It's not Express or node.js doing it. It's whatever code caused or threw the exception in the first place (either manually throwing an exception or the interpreter ran into a error that leads to an exception. That's an exception and where they come from. Because you have wrapped things in an async function, you are likely to see that exception (and it's associated Error object) in your .catch() handler.
There are however situations where you still won't see the exception. If some asynchronous code inside your wrapper uses plain callbacks (not promises) and throws an exception inside that plain asynchronous callback, then your wrapper won't catch that exception (nothing will). That's why all asynchronous code in this architecture should be using promisified asynchronous functions only because it enables the automatic error propagation that you are relying on.
Is there a pattern that ensures that all possible errors that occur in a route are forwarded to the error handling middleware without crashing the server?
No. Not if a function uses plain, non-promisified asynchronous callbacks. As described above, in that circumstance the errors will not propagate up to your wrapper.
FYI, see Express middleware cannot trap errors thrown by async/await, but why? for a scheme for building in rejected promise detection into Express. There's also the Express cousin, koa that does this more automatically as part of its architecture.

Handling errors in an express middleware module

I'm creating a module, which is an express middleware. My question is, when it encounters some kind of error (for example an acl module that sees that the user has no access right to this content), what is the best practice, calling next() with an error, so the app using the module can handle it the way it chooses, or can I send a response and not even call next?
Yes, you pass a error into next function to allow user catch error in callback and do what he needs.
More you can read in this articles:
Who provides the next() function in Express middleware?
https://blog.safaribooksonline.com/2014/03/10/express-js-middleware-demystified/

Express middleware and parameter handling ordering on route

So I am running some API tests and I noticed that one test is failing because it is running some parameter handling logic before middleware, now here is an example of the route definition:
app.post("/something/:some_param",
middlewareA, middlewareB, middlewareC,
function(req, res) {
// Do stuff
});
Now I assumed (wrongly I think) that middleware would be invoked first then it would handle the parameter handler for :some_param however it seems to be the other way around. (by parameter handler I mean app.param())
Problem I have here is that if the above is correct and parameter handlers are run first, some of the logic within the parameter handler assumes the user is logged in already and blows up if they are not, and middlewareA handles user authentication and if they are not logged in redirects them etc, so ideally I would want middlewareA to be called first, so is there a way to achieve this ordering?
The only way I could see this working would be if the parameter handler could utilize middleware but there is no documentation on the API docs on this subject, so is there any best practice to handle this sort of scenario? as I do not want to have to shoe horn my middlewareA logic into my :some-param handling logic as I also have many other :other-param handlers etc which would also need this authentication (and other) middleware run before they run.
Yes, param handlers run before middleware. You can deal with this by either:
recoding your param handler as a middleware. There's not that much difference between the 2 mechanisms.
OR, in your param handler, just run the desired middleware directly as below:
.
function someParam(req, res, next, paramValue) {
myAuthMiddleware(req, res, function (error, result) {
if (error) {
next(error);
return;
}
//Here the user will be logged in
// do what you need to do with req and paramValue
next();
});
}

How to use an error-handler callback in a Sails.js policy?

After asking this question, I've found that I can add a callback array to an endpoint in a sails app like this:
file: /api/policies/somepolicy.js
module.exports = thisIsAnArrayOfCallbacks;
This works ok while each member of thisIsAnArrayOfCallbacks is a function which accepts req, res, and next as arguments. The controller call executes all the functions in the array and the expected result is obtained in a normal flow.
But when using an errorHandler callback (like the one in this example) which takes an additional err parameter, it doesn't work as expected: the express-only version app.get('/path', thisIsAnArrayOfCallbacks) allows the errorHandler to fetch the exception and report a proper response to the client, but when using the sails way, the errorHandler function isn't called and the exception is thrown in the response.
How could I fetch the err parameter or catch the exception occurred in one of the functions of thisIsAnArrayOfCallbacks to send a proper response (a custom one is preferred) to the client?
Thanks in advance.
You're correct in that policies can't be defined as error callbacks; they're solely route-handling middleware and are actually bound to each individual route that they are applied to. Ideally, you'd catch any errors within the policy functions themselves using try/catch and send a response using something like res.forbidden(), res.badRequest(), res.serverError(), etc. In Sails v0.10 you can make any custom response you want and store it in the api/responses folder.
If you really want to implement a catch-all error handler in Sails you have two choices: either override the default 500 handler (in Sails v0.10 this is in /api/responses/serverError, in v0.9.x it's config/500.js), or (in v0.10) create custom Express middleware and load it using sails.config.express.loadMiddleware. See this SO question for details on the second option, and remember to add your custom error handler after the router and before (or in place of) the 500 handler.

Resources