logo cc white
Get Started
Log In
logo cc white
Sign Up
Log In
logo cc white

Best Practices for Error Handling and Logging in MEAN

best practices for error handling and logging in mean mern mevn

Table of content

Whether you’re new to the MEAN stack or a seasoned developer, robust error handling and logging are critical components of any application. This post aims to guide you through best practices for dealing with errors and maintaining logs in a MEAN stack application, using a basic server application as an example.

Looking to practice with us? Explore our demo application available on Code Capsules’ GitHub. Simply click on the provided link to the repo here, and clone the repository to get started.

Why Error Handling and Logging?

Error handling and logging are like the immune system of your software application. They help you identify issues, debug efficiently, and improve the overall quality of your code. Without proper error handling, the application can crash, provide wrong results, or give hackers a potential point of entry. Logging is your lens into what’s happening during execution, providing insights for both development and operations teams.

Error Handling in MEAN Stack

Centralized Error Handling

Centralizing error handling in your MEAN stack application is crucial. This approach ensures that errors are managed consistently across the application. The basic server application demonstrates this with a middleware function that handles errors globally.

// Centralized error handling middleware in the basic server application
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('Something broke!');
});

Use of HTTP Status Codes

Utilizing appropriate HTTP status codes is vital in communicating the nature of errors to clients. In the basic server application, we demonstrate this concept by intentionally triggering an error and responding with a specific HTTP status code.

// Responding with a 400 status code for a specific route
app.get('/error-demo', (req, res, next) => {
    // Trigger an error condition
    const errorCondition = true;
    if (errorCondition) {
        res.status(400).send('Bad Request');
    } else {
        res.send('All good!');
    }
});

Asynchronous Error Handling

Handling errors in asynchronous operations is a key aspect of robust error handling in MEAN stack applications. The following code snippet from our basic server application showcases error handling with async/await.

// Handling errors in asynchronous operations using async/await
app.get('/async-error-demo', async (req, res) => {
    try {
        // Simulate an asynchronous operation that fails
        const result = await someAsyncFunction();
        res.json(result);
    } catch (error) {
        console.error(error);
        res.status(500).send('Error occurred');
    }
});

Use of HTTP Status Codes

Utilizing appropriate HTTP status codes is vital in communicating the nature of errors to clients. In the basic server application, we demonstrate this concept by intentionally triggering an error and responding with a specific HTTP status code.

// Route to demonstrate usage of HTTP status codes
app.get('/error-demo', (req, res) => {
    // Simulating an error condition
    const errorCondition = true;

    if (errorCondition) {
        // Sending a 400 Bad Request response if the error condition is met
        res.status(400).send('Bad Request');
    } else {
        // Sending a 200 OK response in case of no error
        res.send('All good!');
    }
});

Asynchronous Error Handling

Handling errors in asynchronous operations is a key aspect of robust error handling in MEAN stack applications. The following code snippet from our basic server application showcases error handling with async/await.

// Simulating an asynchronous function that might fail
const someAsyncFunction = () => {
    return new Promise((resolve, reject) => {
        // Simulating an asynchronous operation
        setTimeout(() => {
            // Simulating a failure condition
            reject(new Error('Async operation failed'));
        }, 1000);
    });
};

// Route to demonstrate handling errors in asynchronous code
app.get('/async-error-demo', async (req, res) => {
    try {
        // Attempting to execute the asynchronous function
        const result = await someAsyncFunction();
        // Sending the result as a response
        res.json(result);
    } catch (error) {
        // Logging the error to the console
        console.error(error);
        // Sending a 500 Internal Server Error response
        res.status(500).send('Error occurred in async operation');
    }
});

These examples in our basic server application illustrate how to effectively handle errors in different scenarios, ensuring that your application can gracefully manage unexpected situations.

Logging in MEAN Stack

Logging is a crucial part of any application, especially in a MEAN stack application where multiple components interact. Effective logging helps in monitoring the application, diagnosing issues, and understanding user behavior. Below, we integrate basic logging into our server application.

Basic Logging

For the purpose of this demonstration, we’ll use console logging. However, in a production environment, you would typically use more advanced logging mechanisms like Winston or Morgan.

// Middleware for basic logging
app.use((req, res, next) => {
    // Logging each request to the console
    console.log(`Received request on ${req.url}`);
    // Passing control to the next middleware function
    next();
});

This simple logging middleware logs each incoming request, which can be crucial for debugging and monitoring purposes.

Advanced Topics in Error Handling

As your application grows, you might need to implement more advanced error-handling strategies. These ensure that your application can handle errors gracefully even in complex scenarios.

Global Uncaught Exception and Unhandled Rejection Handlers

Setting up global handlers for uncaught exceptions and unhandled promise rejections is a crucial safety measure. It helps catch errors that might otherwise crash your application. However, be cautious with these handlers and ensure to exit the process after logging the error to avoid running in an unstable state.

// Global handler for uncaught exceptions
process.on('uncaughtException', (err) => {
    // Logging the uncaught exception
    console.error(`Uncaught Exception: ${err.message}`);
    // Exiting the process
    process.exit(1);
});

// Global handler for unhandled promise rejections
process.on('unhandledRejection', (reason) => {
    // Logging the unhandled rejection
    console.error(`Unhandled Rejection: ${reason}`);
    // Exiting the process
    process.exit(1);
});

These global handlers provide a last line of defense, ensuring that uncaught exceptions and unhandled promise rejections do not leave the application in an undefined state.

Deployment on Code Capsules

Step 1: Registration on Code Capsules

Start by registering an account on Code Capsules. Follow the steps to create your account and get started.

Register a new account on Code Capsules

Step 2: Logging into Code Capsules

Once registered, log in to your Code Capsules account to begin setting up your project.

Code Capsules login page

Step 3: Creating a Team on Code Capsules

Create a team within Code Capsules. This allows for collaboration and management of your projects with team members.

Code Capsules Dashboard create a new team

Step 4: Creating a Space on Code Capsules

Create a new space in Code Capsules. Spaces are where your projects live and can be configured for different environments.

Code Capsules create a new space

Step 5: Setting Up Your Project Repository

Ensure your project code is pushed to a Git repository. This will allow Code Capsules to fetch your application code directly from the repository for deployment.

// Example: Pushing your code to GitHub
git init
git add .
git commit -m "Initial commit"
git remote add origin YOUR_REPOSITORY_URL
git push -u origin master

Step 6: Connecting Repository to Code Capsules

Link your Git repository to Code Capsules. This allows Code Capsules to fetch your application code directly from the repository for deployment.

// In Code Capsules, navigate to the 'Capsules' section in your space
// Click on 'Connect Repository' and enter your Git repository URL
// Set up the build configurations and environment variables as needed

Connecting your repo
Installing Code Capsules

Step 7: Creating a New Capsule

Within the space you created, start a new capsule. The capsule is your project container where your MEAN stack application will be deployed. Here you can select what your capsule will be used for, whether it is for a front-end, back-end, or database.

Code Capsules - Capsule details

Step 8: Enabling Automatic Deployment

Enable automatic deployment to ensure that every push to your main branch triggers a new build and automatically deploys your application.

Set auto deploy on Code Capsules

Step 9: Verifying Build Success

Verify that your build completes successfully. If there are any errors, the build will fail, and you will need to resolve the issues before restarting the build. Check the build logs for detailed error information.

Build failed on Code Capsules

Step 10: Launching Your Application

Once your build is successful, you will see a green check mark next to the build log. Your application is now live and can be accessed through the provided URL.

Build successful on Code Capsules

Conclusion

This article covered key concepts in error handling and logging in MEAN stack applications, with practical examples from a basic server application, and provided a guide to deploying your application on Code Capsules. By following these best practices and deployment steps, developers can build and deploy robust, maintainable, and secure web applications.

Table of content

chevron-down