Hi All, a little while ago I created a post asking for best practices on error logging with Express. I figured out a pretty lean workflow now and would like to share it with you.First of all it is worth mentioning that express will already catch errors for you and pass it into the next middleware. For example.const express = require('express'); const app = express(); app.get('/', (req, res) => { asd; // This will throw a ReferenceError res.send('Hello World!'); }); app.use((err, req, res, next) => { console.log(err); res.send('Something went horribly wrong'); next(); // Call the next middleware }) app.listen(3000, () => console.log('server started')); In the codeblock navigating to the / route will throw an unhandled error and thus the next middleware will receive the error and you will see Something went horribly wrong in the browser. Instead of logging to the console as I did in the example you should use a package like Winston or a service like Sentry. The code right now is already pretty good, but I like to differentiate between errors I throw and errors the application throws. Therefor I create a custom error you can name it however you want. I use one I found on this gistclass AppError extends Error { constructor(message, status, log) { // Calling parent constructor of base Error class. super(message); // Saving class name in the property of our custom error as a shortcut. this.name = this.constructor.name; // Capturing stack trace, excluding constructor call from it. Error.captureStackTrace(this, this.constructor); // You can use any additional properties you want. // I'm going to use preferred HTTP status for this error types. // `500` is the default value if not specified. this.status = status || 500; // With this property we will determine if we should log this error this.log = log || false; } } I added the log property because most of the time I throw an AppError for things like not matching an user and password and there is no need to log that. Sometimes however a critical piece of code will fail and then its necessary to log. Let's add 2 more routes to the application and modify the middleware to implement the new error class.app.get('/login', (req, res) => { throw new AppError('User not found', 404); res.send('Hello User'); }) app.get('/critical', (req, res) => { throw new AppError('Could not perform critical process', 500, true); res.send('Critical'); }) app.use((err, req, res, next) => { if(err instanceof AppError) { if(err.log) { // Logging is optional for AppError console.log(err); } res.status(err.status).send(err.message); } else { console.log(err); // Errors thrown by the process should allways be logged res.status(500).send('Something went horribly wrong'); } next(); }) As you'd expect navigating to the /login and /critical route will throw and respond with their error messages the only difference is that the /critical route will perform a log. Now this is great, but most of your application will use async code especially something like the loggin in a user. So let's change the login route to an async route and see what happens.app.get('/login', async (req, res) => { throw new AppError('User not found', 404); res.send('Hello User'); }) With the current code you're browser should probably return with a message that it could reach the server. So async functions don't work with error middlewares, but I would never throw you a curve ball this long into reading. The package express-async-errors is as the creator says A dead simple ES6 async/await support hack for ExpressJS. Implementing it is super easy install the package and require it before instantiating the app.const express = require('express'); require('express-async-errors'); const app = express(); Refreshing the page now should show the expected User not found message.Quick note: It's worth mentioning routes returning within the 500 ranges will cause your fetch() calls to throw (probably axios too) so you will have to handle those accordingly.I hope I didn't bore anyone to death with this post, but this process has sped up my development process quite a bit and hopefully it will yours too!
Submitted June 02, 2019 at 03:26PM by runo9
No comments:
Post a Comment