DEV Community

Nikhil Bhutani
Nikhil Bhutani

Posted on

Exception Handling and Logging Errors in REST API using Javascript & Express

Introduction

In this blog we are going to add exception handling to JavaScript REST API by coding our own Exception Middleware. We will also learn how to add multiple exception handlers to our API and build a reusable error module that can be handy to when having multiple repositories in an API. Lastly, we will also see how we can add error logging capabilities to our code which logs errors to a file.


Setup

In this blog I will not be covering how to build a REST API in JavaScript, and I will use the exisiting GroceryAPI that I built in my other blog. It covers all the coding required to build an API from scratch in JavaScript using the Express framework, so do check it out:- Beginner's Guide to REST API in JavaScript using Express

The completed code for this tutorial can be found in the following GitHub Repo in the exception-handling branch.


Code

We'll start by creating a reusable error module.

Create a file named errorHelper.js in the /helpers directory

We will write our first helper method errorBuilder inside of the errorHelpers object which we will export.
errorBuilder will return a custom object to client with status 500 and statusText as "Internal Server Error", the rest of the object will contain tht error message, error number and error syscall. This errorBuilder will accept an error object. We can then use this errorBuilder to build error messages for logging errors to console, logging errors to file etc.



let errorHelpers = {
  errorBuilder: (err) => {
    return {
      status: 500,
      statusText: "Internal Server Error",
      message: err.message,
      error: {
        errno: err.errno,
        call: err.syscall,
        code: "INTERNAL_SERVER_ERROR",
        message: err.message,
      },
    };
  },
};


Enter fullscreen mode Exit fullscreen mode

Now, we create a logErrorsToConsole helper function inside errorHelpers which will use errorBuilder and print the error to the server console whenever it occurs.

In logErrorsToConsole function we simple do a console.error of the error by passing our err object to previously created errorBuilder we simply add * to distinguish the error in the console and then we use the next(err); to move onto the next middleware available.

Now let's configure our middleware in index.js

Simply import the error helper by adding:
let errorHelper = require("./helpers/errorHelpers");

Then, we will add the middleware just after the router configuration.



// Configure router so all routes are prefixed with /api/
app.use("/api/", router);

// Configure exception logger to console
app.use(errorHelper.logErrorsToConsole);


Enter fullscreen mode Exit fullscreen mode

Now to see our error logger middleware work we will change the spelling of the gorceries.json file in the file name variable in groceryRepo.js by removing the s from the const FILE_NAME = "./assets/grocerie.json";

Finally, when we hit the GET request to fetch all groceries we should see the error logged in our terminal like below:

Image description

Adding Error Logging to a log file
So far we setup our own middleware that logs error to console whenever an Internal Server Error occurs.
What if we want the error logged out in a log file that stores all logs of all the errors occured for fututre refernce?

We will achieve this in three steps:
1) Create a logRepo.js file to handle the writes to a log file.
2) Add a helper method to write errors to the log file using the logRepo.
3) Add the helper method as a middleware to our index.js file.

Let's get started!

First step is to create a logRepo.js file in the /repo directory. The code for this will be very similar to the calls to get, update, delete and write data to our grocery store repo.

We create a write function which takes data, req and res as the parameters. On line 7 we create a toWrite variable which will store the information to be logged.

Notice that we have assigned a file to the FILE_NAME field on line 3, make sure to create an empty log.txt file in a logs folder.

We just append all the information that we need to see in our log file such as the Date and Time the error occured, Exception Info and some formatting of the log by appending * at the start and end of the message.

After that we simply use the fs package to write the exception message to the log file on our local file system.

Next, we configure a helper method to log errors to log file in the errorHelpers.js file.

We add the logErrorsToFile method object just after logErrorsToConsole method. The implementation of which is pretty straight-forward. We build the errorObject using our errorBuilder and assign some extra properties to it from the request object. Then we call in the logRepo.write and pass in this errorObject.

NOTE: Don't forget to import the logRepo in errorHelpers.js file at the top.



logErrorsToFile: (err, req, res, next) => {
    let errorObject = errorHelpers.errorBuilder(err);
    errorObject.requestInfo = {
      hostName: req.hostName,
      path: req.path,
      app: req.app,
    };
    logRepo.write(
      errorObject,
      (data) => {
        console.log(data);
      },
      (err) => console.error(err)
    );
    next(err);
  }


Enter fullscreen mode Exit fullscreen mode

Lastly, one final step is to add our middleware to handle this logging functionality in index.js file just after our logErrorsToConsole middleware.



// Configure router so all routes are prefixed with /api/
app.use("/api/", router);

// Configure exception logger to console
app.use(errorHelper.logErrorsToConsole);

// Configure exception logger to console
app.use(errorHelper.logErrorsToFile);



Enter fullscreen mode Exit fullscreen mode

Testing logging to text file
Similar to how we tested our logErrorsToConsole, just remove the appending 's' from the file name in groceryRepo.js and send a GET request to http://localhost:5000/api/

You should see the error logged to console as well as the exception logged to the log.txt file as seen below with Date and Time.

Image description

If you have any doubts you can ask in the comments section below, I will be happy to help.

Happy Coding!


References

https://expressjs.com/en/guide/using-middleware.html
https://expressjs.com/en/guide/error-handling.html

Top comments (1)

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Logging to a file is too 20th century. Better to use, for example, serilogger with an instance of Seq running in Docker.