Is there a way to make ExpressJS log runtime errors? - node.js

I recently ran into an issue where an express route of mine was hanging, and it took me forever to finally figure out that I had a typo in one of my function calls, so it was trying to call a function that did not exist.
For example:
router.get('/example', function(req, res) {
UserService.nonExistentFunction();
res.status(200).send();
});
To me this feels like it should have been something that stuck out like a sore thumb, in the form of a runtime exception in my log. However, the server did nothing, the request just hung silently with no hints as to what went wrong.
Is there a better way to catch these dummy-type errors?

You can define your own error handler in Express.http://expressjs.com/en/guide/error-handling.html
Depends on your perferences, you can log the error in the console or to a file. In my application, I am doing something like this,
import debug = require('debug');
var app = module.exports = express();
var errorLogger = debug('error');
// Error handling
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
// Handle 404
app.use(function(req, res, next) {
res.status(404).send('Sorry cant find that!');
});
function logErrors(err, req, res, next) {
errorLogger(err.stack);
next(err);
}
function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something failed!', status: 500 });
} else {
next(err);
}
}
function errorHandler(err, req, res, next) {
res.status(500);
res.render('error', { error: err, status: 500 });
}

Related

Express error handling - app crashes when error is thrown instead of going into the error handler

I have a problem with my node app. I set up an error handling middleware and when I throw an error in the controller, the app crashes instead of going into the error handler.
ErrorHandler.js
const mongoose = require("mongoose");
exports.ErrorHandler = (err, req, res, next) => {
console.log(err);
if (err instanceof mongoose.Error.ValidationError) {
return res.status(422).json(err.errors);
}
if (err instanceof mongoose.Error.CastError) {
return res.status(404).json({ message: "Resource not found" });
}
return res.status(500).json(err);
};
AuthController.js
static init = async (req, res) => {
throw new NotFoundError("Not found");
}
I didn't know how you're calling the ErrorHandler and if you're using express, but I think you're using it. Although I think I can give to you a simple example of usage of ErrorHandler as middleware:
function errorHandler(error, req, res, next) {
res.status(error.status || 500);
res.send({
error: {
message: error.message,
},
});
}
// Error-handling middleware
app.use(errorHandler);
//example
app.get('/', function (req, res, next) {
next(new Error('Error for understanding the ErrorHandler'));
});
In this example your app won't crashes.
Please read this official guide to complete understand how it works: https://expressjs.com/en/guide/error-handling.html

What are different between next(error) and throw new Error in Express framework?

Can someone explain to me about the different between two ways exception error handling in code Express JS below:
const express = require('express');
const app = express();
app.get('/test', (req, res, next) => {
// the first way:
throw new Error('my error message');
// the second way:
next(new Error('my error message'));
});
app.use((err, req, res, next) => {
res.status(err.status || 500).send(err.message || 'Internal Server Error');
});
app.listen(3000, () => console.log('Welcome to ExpressJS'));
It returns the same result handled by error middleware but what is the difference here?
Nothing, based on the source code.
try {
fn(req, res, next);
} catch (err) {
next(err);
}

How to to create a custom logger in Express?

During an exercise in school we have been tasked with making custom middleware in Express:
This might be tricky. Make it so that your custom logging middleware
also logs out the eventual response status code. For example, after a
successful GET request to / you should see:
GET / 200
I tried this:
app.use(function(req, res, next) {
console.log(chalk.green(req.method, req.url, res.statusCode));
next();
});
It appears to work but then I noticed upon trying a uri which doesn't exist I still get:
GET /foo 200
Does this mean the request i.e. GET, is working but has nothing to do if the resource is there?
Also how would I implement error handling, in this instance I tried:
app.use(function(err, req, res, next) {
if (err) {
console.log(err);
} else {
console.log(chalk.green(req.method, req.url, res.statusCode));
}
next();
});
But that didn't work at all!
Thanks in advance!
app.use(function(req, res, next) {
if (res.headersSent) {
console.log(chalk.green(req.method, req.url, res.statusCode));
} else {
res.on('finish', function() {
console.log(chalk.green(req.method, req.url, res.statusCode));
})
}
next();
});

Correct way to handle 404 and 500 errors in express

What is the right way to handle 404 and 500 errors in express and handle them properly.I was reading some posts that explain different ways of handling 404 errors. One was using handler for * route at the end
app.get('*',function(req,res){
res.render('404');
}
);
Another one I come across was using middlewares, as below
var express=require('express');
var app=express();
var routes=require('./routes/route.js');
app.set('view engine','ejs');
app.use(express.static(__dirname + '/public'));
app.get('/',routes.home);
app.get('/login',routes.login);
//Handling 404
app.use(function(req, res) {
res.status(404).render('404');
});
// Handling 500
app.use(function(error, req, res, next) {
res.status(500).render('500');
});
var port = process.env.PORT || 3000;
var server=app.listen(port,function(req,res){
console.log("Catch the action at http://localhost:"+port);
});
I am using middleware approach, but it works only when I put those middlewares at the end, which is after all the route handlers. If I put both the middlewares before the route handler for '/' and '/login', It does not works.
Is this the right way to handle 404 and 500 errors?
I've found that using the method that express-generator uses to be ideal. At the end of all of your routes you include:
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
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.render('error', {
message: err.message,
error: {}
});
});
And then an example route (than could have errors) could look like this:
router.get('/', function(req, res, next) {
err = { message: 'Example error message', error: 'Some error'}
if(err) next(err);
if(!err){
res.render('index', { title: 'Express' });
}
});
As #weiyin mentioned, it's probably a good idea to at-least log your errors to help keep an eye on when things do go wrong.
Express matches routes in the order you add them, so that's why the catch-all 404 route only works if you put it at the end. Handling 500 errors that way is fine, but at the very least you should log them too.

Express js error handling

I'm trying to get error handling running with express but instead of seeing a response of "error!!!" like I expect I see "some exception" on the console and then the process is killed. Is this how error handing is supposed to be setup and if so is there another way to catch errors?
var express = require('express');
var app = express();
app.use(function(err, req, res, next) {
console.log("error!!!");
res.send("error!!!");
});
app.get('/', function(request, response) {
throw "some exception";
response.send('Hello World!');
});
app.listen(5000, function() {
console.log("Listening on 5000");
});
An example app/guide on error handling is available at
https://expressjs.com/en/guide/error-handling.html
However should fix your code:
// Require Dependencies
var express = require('express');
var app = express();
// Middleware
app.use(app.router); // you need this line so the .get etc. routes are run and if an error within, then the error is parsed to the next middleware (your error reporter)
app.use(function(err, req, res, next) {
if(!err) return next(); // you also need this line
console.log("error!!!");
res.send("error!!!");
});
// Routes
app.get('/', function(request, response) {
throw "some exception";
response.send('Hello World!');
});
// Listen
app.listen(5000, function() {
console.log("Listening on 5000");
});
A few tips:
1) Your code wasn't working because your error handler middleware was run before your route was reached, so the error handler never had a chance to have the error passed to it. This style is known as continuation passing. Put your error handler last in the middleware stack.
2) You should shut down the server when you have an unhandled error. The best way to do that is to call server.close(), where server is the result of doing var server = http.createServer(app);
Which means, you should do something like this:
var server = http.createServer(app);
app.use(function(err, req, res, next) {
console.log("error!!!");
res.send("error!!!");
server.close();
});
You should probably also time out the server.close(), in case it can't complete (your app is in an undefined state, after all):
var server = http.createServer(app);
app.use(function(err, req, res, next) {
console.log("error!!!");
res.send("error!!!");
server.close();
setTimeout(function () {
process.exit(1);
}, 3*1000);
});
I made a library that does all this for you, and lets you define custom responses, including specialized error views, static files to serve, etc...:
https://github.com/ericelliott/express-error-handler
I had the same problem and couldn't figure out what was wrong.
The thing is if you have the express errorHandler defined then your custom error handler is never being called.
If you have the next code, simply remove it:
if ('development' === app.get('env')) {
app.use(express.errorHandler());
}
Worked for me:)
Installing express install connect-domain, then something like this:
var express = require("express"),
connectDomain = require("connect-domain"),
app = express(),
errorHandler;
// Our error handler
app.use(connectDomain());
errorHandler = function (err, req, res, next) {
res.send(500, {
"status": "error",
"message": err.message
});
console.log(err);
};
Then when setting up your endpoints, tack errorHandler on the end in a use():
app.get("/some/data", function (req, res) {
// ... do some stuff ...
res.send(200, "Yay! Happy Success!");
}).use(errorHandler);
Create an error function:
function throwError(status, code, message) {
const error = new Error(message);
error.name = '';
error.status = status;
error.code = code;
throw error;
}
e.g.
throwError(422, 'InvalidEmail', '`email` should be a valid email address')
We assign name to '' so that when we toString the error it doesn't prepend it with "Error: "
As mentioned if you're using express you can create a special error handling middleware by specifying 4 arguments:
app.use((err, req, res, next) => {
if (err) {
res.status(err.status || 500).json({ code: err.code || 'Error', message: err.toString() });
}
});
If you're not using express or otherwise prefer, add that code to your catch handler instead.
Why?
Modern apps handle JSON, throwing errors in JSON makes more sense and results in cleaner UI code.
You should not only throw error messages because they are imprecise to parse. What if the UI is a multilingual app? In that case they can use the code to show a localized message.
Found that recipes from here and even in official documentation brake logging for advanced loggers like pino-http (at least for latest express4). Problem appears when you write like this:
app.use((err, req, res, next) => {
if (!err) {
return next();
}
res.status(err.status || 500).json({ error });
});
Express "thinks" that it's normal result and logger does not log error.
{
...
"res":{"status":400},
"msg":"request completed"
}
Fix here (the first line):
res.err = err;
res.status(err.status || 500).json({ error });
Log output after the fix:
{
...
"res":{"status":400},
"msg":"request errored",
"err":{"type":"Error","message":"Some error","stack":"..skip.."}
}

Resources