avatarOren Holis

Summary

The article presents a method for simplifying error handling in Node.js Express applications by introducing a custom ApiError class and a middleware solution that streamlines the process of returning JSON responses and handling errors consistently.

Abstract

The provided content discusses a common challenge faced by Node.js and Express developers: efficiently handling errors without cluttering the codebase with repetitive boilerplate. The author proposes a solution involving the creation of an ApiError class to standardize error objects and a middleware function that automatically processes these errors and sends appropriate JSON responses. This approach not only reduces the amount of code but also improves readability and maintainability by allowing developers to throw errors which are then caught and handled by the middleware. The article also includes a practical example of how to implement this solution in an Express application, demonstrating how it can be used to handle both synchronous and asynchronous errors, and concludes by encouraging developers to adopt this method to enhance their development workflow.

Opinions

  • The author believes that the traditional method of handling errors in Express applications leads to excessive boilerplate code, which makes the code less readable and maintainable.
  • A strong opinion is held that all errors should adhere to a unified JSON structure to facilitate easy processing on the frontend.
  • The author suggests that the proposed error handling foundation meets all the requirements for efficient error management in Express applications.
  • The article conveys the opinion that the introduced middleware wrapper significantly simplifies the codebase by allowing developers to throw errors instead of manually sending error responses.
  • The author is confident that the described solution will make Node.js Express applications easier to write and maintain, suggesting it as a best practice for developers.
(Source: https://www.digitalocean.com/community/tutorials/how-to-use-the-node-js-repl)

What Is The Best Node Js Express Shortcut, that will blow your mind?

Building web applications with nodejs and express has become the industry standard. Yet, so many developers still have to write complex code with lots of error-handling boilerplate code. I have found this simple solution, yet saving you hundreds of lines of boilerplate implementing small Express js middleware I am going to show you.

The problem

Every express developer has been facing the issue how to efficiently handle errors. I have seen countless times developers stick to this syntax:

if (notFound) {
    res.send(404, {
        message: 'Not found'
    });
    return;
}

Resolving http errors like this leads to lot of boilerplate and makes the code less readable. So how do we simplify it?

The solution

Firstly we need to make a strong foundation for handling errors. Code should provide simple extendable error resolution, even for unhandled exceptions thrown by poorly written code or calling some function on null. All the errors should have the same JSON structure for easy processing on the frontend in the web application.

The foundation can look like this:

class ApiError extends Error {
 constructor(status, msg, code, detail) {
  super(msg);

  this.status = status;
  this.code = code;
  this.detail = detail;
 }
}

function handle_error(err, res) {
 let status = 500;
 let error = {
  error: 'Internal error',
 };

 // unified error returning interface for JSON endpoints
 if (err instanceof ApiError) {
  status = err.status;
  error.error = err.message;
  error.code = err.code;
  error.detail = err.detail;
 } else if (err instanceof Error) {
  error.error = err.message;
  console.log(err);
  Logger.fatal(`Unhandled failure of server, ${res.req.method} ${res.req.originalUrl}:\n status code 500, error ${err.message} \n ${err?.stack}`);
 }

 // don't cache error responses
 res.set('Cache-Control', 'no-store');
 res.status(status);
 res.json(error);
}

This code meets all the requirements mentioned above. Now for the fun part, we need to implement this for all endpoints in our application.

So we can move from this:

if (notFound) {
    res.send(404, {
        message: 'Not found'
    });
    return;
}

to this:

if (notFound) {
    throw new ApiError(404, 'Not found');
}

For this purpose will create a middleware wrapper for express HTTP functions for easy implementation, even in later stages of development.

const FallThrough = Symbol('api-fall-through');

function async_json_middleware(fn) {
 return function(req, res, next) {
  try {
   // some defaults for JSON endpoints
   req.res.set('Cache-Control', 'no-store');

   Promise.resolve(fn(req, res)).then(data => {
    if (data === undefined) {
     res.json(null);
    } else if (data === FallThrough) {
     next();
    } else {
     res.json(data);
    }
   }, err => handle_error(err, res));
  } catch(err) {
   return handle_error(err, res);
  }
 };
}

['get', 'post', 'put', 'delete', 'all'].forEach(function(m) {
 express.application[m + '_json'] = function(path, fn) {
  this[m](path, async_json_middleware(fn));
 }
});

This express middleware brings us 2 important improvements. We can now return value from the endpoint function, and it will do the same as sending res.json with http status code 200. And secondly more importantly we can throw errors in our code. Significantly simplifying our codebase, eliminating the need for res.send and termination of our function with return.

app.get_json('/api/good-morning', async req => {
  const now = new Date();
  if (now.getHours() < 6) {
    throw new ApiError(400, 'It's not morning, yet');
  }
  if (now.getHours() > 10) {
    throw new ApiError(400, 'It's not morning anymore');
  }
  return 'Good morning';
});

Conclusion

The solution I have described above has helped me through the years making my node js express applications easier to write with less boilerplate. If thi stutorial has helped you do not mind leaving clap or check my other articles.

JavaScript
Javascript Tips
Expressjs
Nodejs
Node Js Tutorial
Recommended from ReadMedium