default error handler when multiple calls to next(error) - node.js

The express doc says:
Note that the default error handler can get triggered if you call
next() with an error in your code more than once, even if custom error
handling middleware is in place.
I think it means if we call next(error) inside our custom error handler, then the control passes on to next error handler (which may be the express' default one if we already has not registered more custom error handlers).
Is my understanding correct?

Yes, you have understood it correctly. However, it is not useful to call the default error handler inside the custom error handler as the only purpose of the custom error handler is to send the errors to the user according to you i.e. in your format.
You can implement a custom global error handler by defining an error-handling middleware after all the app.use calls and in the callback function, you can create your own logic like sending different errors in dev or prod environment. You can also set up different user-friendly messages.
app.use(function (err, req, res, next) {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'development') {
// a custom function for sending dev errors
sendErrorDev(err, res);
} else if (process.env.NODE_ENV === 'production') {
// logic for creating different user-friendly errors
sendErrorProd(error, res);
}
})
And in both sendErrorDev and sendErrorProd functions, you can send the errors by the res object.

Related

Express js middleware not working when error is passed alongside ,req,res and next

So , I am trying to implement CSRUF in express and I want to have custom errors thrown instead of the default error handling of the middleware CSRUF example here.
The CSRF implemntetion is working correctly and when the token is invalid,an error is thrown in console and a response with a 403 status is send to browser.
I do not want the error to be handled by default.
When I create a custom error handler middleware as below,
function (err,req, res, next) {
console.log("reached")
if (err.code !== 'EBADCSRFTOKEN') return next(err)
console.log("Not working")
// handle CSRF token errors here
res.status(500)
res.send('form tampered with')
}
It appears that the middlware is not being implemented as the default error for CSRUF is being thrown.
Intrestingly,I noticed that when i have a custom middeware with an err parameter,the middleware appears to be ignored by the app.
Example(This works)
function (req, res, next) {
console.log("This is some middleware") //Console outputs
next()
}
However,When I add a err or error parameter to the function as below,it appears as though the middleware is not being used
function (req, res, next) {
console.log("This is some middleware.Err parameter has been passed") //Nothing is output to console
next()
}
I have read the Express error handling documentation and done as required but i still face the error,What could be the issue and how do i handle such.
I finally figured it out.
When I place the error handler middleware just after the CSRUF everything works i.e
app.post(route,middleware1,errorhandler,(req,res)={
//Any errors from middleware1 will now be catched by the errorhandler instead of the default error handler
//Some code here
})
The location of the errorhandler appears to play a big role

Prevent stack trace leak in production in Nodejs application

I was looking at this Nodejs express Guthub repo. The production strack trace leak prevention is done using:
// development error handler
// will print stacktrace
if (!isProduction) {
app.use(function(err, req, res, next) {
console.log(err.stack);
res.status(err.status || 500);
res.json({'errors': {
message: err.message,
error: err
}});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.json({'errors': {
message: err.message,
error: {}
}});
});
I do not understand why the production strack trace middleware does not have to be inside the else condition
In the example you shared, an else block would probably make things a bit more clear, but it's not strictly needed. If isProduction is truthy, the error handling middleware inside the if block will handle the error. Since it does not call next(err); to pass the request to the next middleware, control will not be passed to the following "production" error-handling middleware. The response is sent and Express is done handling this particular request.
If isProduction is falsey, obviously the "development" middleware is not ever registered with Express and all errors will be handled in the "production" error-handler.
The above example, however, would break down if you needed to add another error-handling middleware after the "production" error-handler or something.
More Details
In Express, middlewares are run sequentially in the order in which they were registered and control is passed to the next middleware by using the calling the next parameter. See the documentation here.
Error handling middleware, like the ones posted in your example, work the same way. The error will reach these middlewares because a previous middleware called next and passed an error like so: next(new Error('Something went wrong));.

Nodejs handle unsupported URLs and request types

I would like to add to my web service an option to handle unsupported URLs, I should mention that I'm using Express.
In order to handle bad URLs, (code 404), I tried using
app.use(app.router);
But apparently it's deprecated, what other solutions can I use?
I saw this suggested solution but I would like to hear about other alternatives first.
In addition, my web service support a few HTTP request types, such as GET and POST, how do I properly respond to request types that I do not support? such as DELETE.
The behavior I would like to have is that in case of 404 error, I will return an appropriate response message that's all. Same in case of unsupported requests.
For example:
response.status(404).json({success: false,msg: 'Invalid URL'});
A 404 handler for all unhandled requests in Express would typically look like this:
app.use(function(req, res, next) {
res.status(404).sendFile(localPathToYour404Page);
});
You just make this the last route that you register and it will get called if no other routes have handled the request.
This will also catch methods that you don't support such as DELETE. If you want to customize the response based on what was requested, then you can just put whatever detection and customization code you want inside that above handler.
For example, if you wanted to detect a DELETE request, you could do this:
app.use(function(req, res, next) {
if (req.method === "DELETE") {
res.status(404).sendFile(localPathToYour404DeletePage);
} else {
res.status(404).sendFile(localPathToYour404Page);
}
});
Or, if your response is JSON:
app.use(function(req, res, next) {
let obj = {success: false};
if (req.method === "DELETE") {
obj.msg = "DELETE method not supported";
} else {
obj.msg = "Invalid URL";
}
res.status(404).json(obj);
});
Some references:
Express FAQ: How do I handle 404 responses?
Express Custom Error Pages
And, while you're at it, you should probably put in an Express error handler too:
// note that this has four arguments compared to regular middleware that
// has three arguments
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
});
This allows you to handle the case where any of your middleware encountered an error and called next(err).

Automatically log HTTP 500 responses in Express?

A common pattern in my Express app is to include the following in all my routes:
//...code which could result in an err
if (!err) return res.send(200);
console.log(err); // Would prefer to omit this line
res.send(500);
Right now, I need to write console.log(err) in all my routes. I'd prefer to just automatically log the err variable every time a 500 is sent. Is there any way to hook into Express and automatically log the call stack and/or err for all 500 responses?
From your explanation, you seem to be including error handling in all your routes.
You probably should create a global interceptor error handler which can perform the logging for you and still be the base error handler if you have a 500 error type.
//if your express var is app
var errorHandler = function(err, req, res, next){
console.log(err.stack);
res.send(500);
// or you could call res.render('error'); if you have a view for that.
};
app.use(app.router); // this has to come before your interceptors
app.use(notFound); // your page not found interceptor
app.use(errorHandler);

Centralizing error handling in an express.js-based app

I just recently started working on an express.js based application, which also uses the pg module (https://github.com/brianc/node-postgres)
I also spent a significant amount of time, reading about node and express approach error handling, the benefits of properly designing middleware, etc. Yet, a recurring problem is still buzzing me without a solution.
Say, I have the following router method:
app.get("/:someThing/:someId", function(req, res, next) {
pgClient.query("some SQL query", function(err, data) {
if (err) { return next(err); } // some 500 handler will take it
if (data.rows.length == 0) {
next(); // send it over to a 404 handler
}
//finally, here we get the chance to do something with the data.
//and send it over via res.json or something else
});
});
If I've read correctly, this should be the proper way to do it. Yet, I bet you can also admt that it is too much of boilerplate to rewrite over and over ... and over again, even in the very same router method, in case we have multiple nested callbacks.
I've been asking myself what the best way to handle such a situation centrally would be. All of my ideas involve intercepting the pgClient.query method. In one, the query method will simply throw the error instead of passing it to the callback. In another, the call to the pgClient.query will send the router method's next to pgClient. Then the intercepted query method will know how to deal with the next being passed to it.
From what I know, throwing errors around is not really the appropriate way to get it to the 500 handlers. On another hand, passin next as an option to pgClient, gives such a low level a lot of knowledge about the the layers above, which based on my knowledge and experience, can lead to coupling, and is not very good either.
What do you suggest?
You can use connect-domain middleware. It works with connect and express and based on Doman API.
You need to add connect-domain middleware as first middleware in stack. Thats all. Now you can throw errors everywhere in your async code and they will be handled with domain middleware and passed to express error handler.
Simple example:
// Some async function that can throw error
var asyncFunction = function(callback) {
process.nextTick(function() {
if (Math.random() > 0.5) {
throw new Error('Some error');
}
callback();
});
};
var express = require('express');
var connectDomain = require('connect-domain');
var app = express();
app.use(connectDomain());
// We need to add router middleware before custom error handler
app.use(app.router);
// Common error handler (all errors will be passed here)
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
app.listen(3131);
// Simple route
app.get('/', function(req, res, next) {
asyncFunction(function() {
res.send(200, 'OK');
});
});

Resources