Open In App

Explain Error Handling in Express.js using an Example

Last Updated : 16 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Error handling in Express.js refers to the process of capturing and responding to errors that occur during the execution of an Express application. In Express, you can handle errors using middleware functions, which are functions that have access to the request and response objects, as well as the next middleware function in the application’s request-response cycle.

Express has built-in error handling middleware, such as the app.use(function(err, req, res, next) {}) function, which can be used to handle errors that are thrown or passed to the next() function. You can also create your own error-handling middleware functions to handle specific errors in your application.

It’s important to note that in Express, the order of middleware functions is important. Error-handling middleware should be placed at the end of the middleware stack, after all, other middleware functions, so that it can catch any errors that are not handled by the other middleware.

In addition, it’s important to handle errors properly and provide a proper error message to the user, rather than returning stack traces to the client in production.

Reason for using error handling used in express.js:

  • To prevent application crashes: Without error handling, unhandled errors can cause an application to crash, leading to poor user experience and potential data loss. Error handling allows you to capture and respond to errors, preventing them from causing a crash and keeping the application running smoothly.
  • To provide meaningful error messages: Error handling allows you to provide meaningful and user-friendly error messages to your users, rather than leaving them with a blank screen or a default error message. This can help to improve the overall user experience and prevent confusion or frustration.
  • To improve debugging: Error handling allows you to capture and log errors, making it easier to debug your application and identify the root cause of any issues. This can save time and effort when troubleshooting problems with your application.
  • To comply with standards and regulations: Proper error handling is often a requirement for compliance with security standards and regulations. By handling errors correctly, you can ensure that your application meets these standards and regulations.

Ways to Perform Error Handling:

1. Middleware function: Express.js has built-in support for error-handling middleware, which allows you to handle errors that occur during the execution of the application.

Syntax:

app.use(function(error, request, response, next) {
       // Handle the error
       response.status(500).send('Internal Server Error');
});

2. Try-Catch statements: you can use try-catch statements to handle errors that occur within specific blocks of code. This ensures that any errors that occur are caught and handled in a controlled manner.

Syntax:

app.get('/', function (req, res) {
    try {
        // Code that might throw an error
    } catch (error) {
        // Handle the error
        res.status(500).send('Internal Server Error');
    }
});

3. Error logging: You can set up error logging so that any errors that occur during the execution of the application are logged to a file or a database for later analysis.

Syntax:

app.get('/', function (req, res) {
    try {
       throw new Error('Something went wrong');
    } catch (error) {
      console.error(error);
    }
});

Error codes: You can set up error codes for different types of errors that occur during the execution of the application. This makes it easier to identify and handle specific errors.

  • Error codes in Node.js are symbolic values that represent specific types of errors that can occur during the execution of a program. Error codes are usually represented as strings and are used to help identify and categorize different types of errors.
  • For example, the Node.js fs module uses error codes such as ‘ENOENT’ (no such file or directory) or ‘EACCES’ (permission denied) to represent specific types of file system errors.
  • When an error occurs in your Node.js application, you can access the error code by checking the code property of the error object. For example, if you are using the fs.readFile function, you can check the code property of the error object that is passed to the callback to determine the type of error that has occurred.

Example:

const fs = require('fs');

fs.readFile('nonexistent-file.txt', (error, data) => {
    if (error) {
        console.error(error.code);
    } else {
        console.log(data.toString());
    }
});

4. HTTP status codes: You can use HTTP status codes to indicate the type of error that occurred. For example, a status code of 400 (Bad Request) can indicate a validation error, while a status code of 500 (Internal Server Error) can indicate a server-side error.

Syntax:

 const http = require('http');

const server = http.createServer((request, response) => {
  response.statusCode = 200;
  response.end('OK');
});

server.listen(8080);
  • By using any of the above, you can handle errors in a controlled and efficient manner, and ensure that your application is robust and stable.

Let’s see some basic examples and explanations for Error Handling in Express.js:

Example 1: Using a middleware function: You can use a middleware function to handle errors that occur during the execution of an application. The middleware function should have four arguments: error, request, response, and next.

Javascript




const express = require('express');
const app = express();
  
// Custom error handling middleware
const errorHandler = (err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('Something went wrong!');
};
  
app.use((req, res, next) => {
    throw new Error('Something broke!');
});
  
// Use the custom error handling middleware
app.use(errorHandler);
  
app.listen(3000, () => {
    console.log('App is listening on port 3000');
});


Steps to run the application: Write the below code in the terminal to run the application:

node index.js

Output: 

 

Explanation: 

  • In this example, we define a custom error-handling middleware function errorhandler that logs the error stack and sends a response with a status code of 500 and the message “Something went wrong!”.
  • We then use the custom error handling middleware by adding the app.use(errorhandler) after defining it.
  • This error-handling middleware will catch any errors thrown in the previous middleware or routes, and handle them according to the logic defined in the errorHandler function.
  • The first line App is listening on port 3000 is logged when the Express app starts listening on port 3000.
  • If you make a request to the app, the custom middleware will throw an error, which will then be caught by the error-handling middleware. The error stack trace will be logged to the console, and the response sent to the client will have a status code of 500 and the message “Something went wrong!”.

Example 2: Using the try-catch statement: You can use the try-catch statement to handle errors that occur within a specific block of code.

Javascript




const express = require('express');
const app = express();
  
app.get('/', (req, res, next) => {
    try {
        // Some code that might throw an error
        const data = someFunctionThatMightThrowError();
        res.status(200).json(
            { message: 'Data retrieved successfully', data });
    } catch (error) {
        next(error);
    }
});
  
// Custom error handling middleware
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json(
        { message: 'Something went wrong!' });
});
  
app.listen(3000, () => {
    console.log('App is listening on port 3000');
});


Explanation:

  • In this example, we wrap the code that might throw an error in a try block. If an error is thrown, it will be caught by the corresponding catch block, which logs the error stack and sends a response with a status code of 500 and the message “Something went wrong!”.
  • This approach allows for more fine-grained error handling, as the try-catch statement can be used multiple times in different middleware functions or routes.

Steps to run the application: Write the below code in the terminal to run the application:

node index.js

Output:

 

Explanation:

  • If you make a request to the app, the custom middleware will throw an error, which will then be caught by the try-catch statement. The error stack trace will be logged to the console, and the response sent to the client will have a status code of 500 and the message “Something went wrong!”.
  • Note that the [ERROR STACK TRACE] part of the output will vary depending on the exact error that was thrown. It will contain details about the error, such as the error message and the location in the code where the error was thrown.
  • his output will be displayed if you make a request to the app and an error is thrown by the custom middleware. The error stack trace will be logged to the console and the response sent to the client will have a status code of 500 and the message “Something went wrong!”.
  • This output will be displayed when the Express app starts listening on port 3000. No error will be thrown if you do not make any requests to the app.

Example 3: Using the next() function: You can use the next() function to pass errors to the next middleware function in the chain.

Javascript




const express = require('express');
const app = express();
  
app.get('/', (req, res, next) => {
    // Some code that might throw an error
    const data = someFunctionThatMightThrowError();
    if (!data) {
        return next(new Error('Error retrieving data'));
    }
    res.status(200).json(
        { message: 'Data retrieved successfully', data });
});
  
// Custom error handling middleware
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).json(
        { message: 'Something went wrong!' });
});
  
app.listen(3000, () => {
    console.log('App is listening on port 3000');
});


Explanation: 

  • In this example, we have two middleware functions. The first middleware function throws an error, and the second middleware function is used for error handling. If an error is thrown in the first middleware function, the control flow is passed to the second middleware function using the next() function. The error is then logged to the console and a response with a status code of 500 and the message “Something went wrong!” is sent to the client.
  • This approach allows for error handling to be handled separately from the middleware functions that perform the core functionality of the application.

Steps to run the application: Write the below code in the terminal to run the application:

node index.js

Here’s an example using curl:

  • Open a terminal or command prompt.
  • Navigate to the directory where the program is located.
  • Start the application by running node app.js.
  • In another terminal window, run the following command to make a request to the ‘/’ endpoint:
curl http://localhost:3000

Output:

 

  • If you make a request to the app, the first middleware function will throw an error. The error will be passed to the second middleware function using the next() function, where it will be logged to the console and a response with a status code of 500 and the message “Something went wrong!” will be sent to the client.
  • Note that the [ERROR STACK TRACE] part of the output will vary depending on the exact error that was thrown. It will contain details about the error, such as the error message and the location in the code where the error was thrown.

Advantages of error handling used in express.js:

  1. Improved user experience: Error handling allows you to provide meaningful and user-friendly error messages to your users, rather than leaving them with a blank screen or a default error message. This improves the overall user experience and can help to prevent confusion or frustration.
  2. Better debugging: When errors occur in an application, it can be difficult to identify the cause without proper error handling. By capturing and logging errors, you can more easily debug your application and identify the root cause of any issues.
  3. Increased application stability: Error handling helps to prevent unhandled errors from crashing your application, which can lead to increased stability and fewer downtime incidents.
  4. Better maintainability: Error handling makes it easier to maintain your application by providing a clear and consistent way to handle errors. This can make it easier to identify and fix bugs, as well as to add new features.

Disadvantages of error handling used in express.js:

  1. Increased complexity: Error handling can add complexity to your application, as it requires you to anticipate and plan for potential errors. This can make your code more difficult to understand and maintain.
  2. Overhead: Error handling can add overhead to your application, as it requires additional logic and processing to capture and respond to errors. This can impact the performance of your application.
  3. False alarms: If error handling is not implemented correctly, it can lead to false alarms or unnecessary error messages being displayed to users. This can create confusion and damage user trust.
  4. Security risks: Improper error handling can create security risks, as it can reveal sensitive information or provide attackers with clues about potential vulnerabilities in your application.


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads