Skip to content

Implement Centralized Error Handling Middleware and Custom Error Classes #70

@rishabh0510rishabh

Description

@rishabh0510rishabh

Problem Statement

Currently, the backend codebase lacks a unified strategy for handling exceptions. Error handling is likely performed locally within individual controllers using repetitive try-catch blocks. This results in code duplication, inconsistent API error response structures (e.g., varying field names for error messages), and difficulty in debugging due to unmanaged stack traces. To maintain a robust backend architecture, we need to standardize how errors are generated and sent to the client.

Current Behavior / Limitation

  • Inconsistency: Some controllers may return { error: "message" }, while others return { message: "error" } or just a plain string.
  • Redundancy: Developers have to manually set HTTP status codes and write JSON response logic in every catch block.
  • Visibility: Stack traces might be inadvertently exposed in production or missing in development environments where they are needed for debugging.

Expected Improvement

After this refactor, the application should utilize a global error handling mechanism. Controllers will simply pass errors to the next() function. The API will produce a consistent error contract:

{
  "status": "fail", // or "error"
  "message": "Resource not found",
  "stack": "..." // Only present in development mode
}

Proposed Approach

  1. Create server/utils/AppError.js:

    • Create a custom class extending the native JS Error class.
    • It should accept message and statusCode in the constructor.
    • Set this.isOperational = true (to distinguish operational errors from programming bugs).
  2. Create server/middleware/errorMiddleware.js:

    • Implement a standard Express error handling function signature: (err, req, res, next).
    • Default the status code to 500 if not set.
    • Development Mode: Send statusCode, status, message, and stack.
    • Production Mode: Send clean error messages. Do not leak stack traces.
  3. Update server/index.js:

    • Import and use the global error handler middleware after all route declarations.
    • Add a handler for unhandled routes (404) that forwards an AppError to the global handler.
  4. Refactor Controllers (server/controllers/*.js):

    • Replace manual res.status(x).json(...) error responses with next(new AppError('Message', statusCode)).

Verification Steps

To verify that the centralized error handling is working correctly, follow these steps:

  1. Setup: Ensure the server is running (npm run dev or npm start).
  2. Test 404 (Not Found):
    • Open Postman or your browser.
    • Send a request to a non-existent route, e.g., GET http://localhost:5000/api/non-existent-route.
    • Verify: You receive a JSON response with status 404 and a standard error message.
  3. Test Operational Error:
    • Temporarily modify a controller (e.g., in authController) to throw a new AppError('Test error', 400).
    • Trigger that controller endpoint.
    • Verify: The response is a 400 Bad Request with your custom message.
  4. Test Environment Logic:
    • Check the response body. If NODE_ENV=development, you should see the stack property.
    • Set NODE_ENV=production in your .env file and restart the server.
    • Trigger the error again.
    • Verify: The stack property is absent from the response.

Labels: ECWoC26

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions