Smart Library Docs

Error Handling & API Response Format

Standardized enterprise error handling with machine-readable error codes, validation error mapping, and consistent API response contracts.

Error Handling & API Response Format

The SLMS enforces a single, predictable API response contract across all endpoints. Every response — success or failure — follows the same shape, enabling the frontend to interpret responses programmatically via error codes rather than message text parsing.


Response Contracts

Success Response

{
  "success": true,
  "message": "Book created successfully.",
  "data": { ... }
}

Error Response

{
  "success": false,
  "code": "VALIDATION_FAILED",
  "message": "Validation failed.",
  "errors": {
    "email": "Email is required.",
    "password": "Must be at least 12 characters."
  }
}

Error Response (No Field Errors)

{
  "success": false,
  "code": "RATE_LIMITED",
  "message": "Too many requests, please try again later."
}

APIError Class

File: backend/utils/apiError.js

class APIError extends Error {
  constructor(message, statusCode, code = 'SERVER_ERROR', errors = null, isOperational = true) {
    super(message);
    this.statusCode = statusCode;
    this.code = code;          // Machine-readable error identifier
    this.errors = errors;      // Optional field-level validation errors
    this.isOperational = isOperational;
  }
}

Usage in Services / Controllers

// Simple error
throw new APIError('User not found', 404, 'RESOURCE_NOT_FOUND');

// Validation error with field details
throw new APIError('Validation failed.', 400, 'VALIDATION_FAILED', {
  email: 'Email is required.',
  password: 'Must be at least 12 characters.'
});

Error Handler Middleware

File: backend/middleware/errorHandler.js

The global error handler catches all errors passed to next(err) and maps them to standardized codes:

Error SourceMapped CodeStatus
Mongoose CastErrorRESOURCE_NOT_FOUND404
Mongoose duplicate key (11000)DUPLICATE_RESOURCE400
Mongoose ValidationErrorVALIDATION_FAILED400
JsonWebTokenErrorAUTH_INVALID401
TokenExpiredErrorTOKEN_EXPIRED401
Body-parser SyntaxErrorINVALID_PAYLOAD400
rate-limiter-flexible rejectionRATE_LIMITED429
Unhandled / unknownSERVER_ERROR500

Automatic Validation Error Extraction

When Mongoose throws a ValidationError, the handler automatically extracts per-field error messages into the errors object:

// Mongoose throws: { errors: { email: { message: "Email is required" }, ... } }
// Handler returns:
{
  "success": false,
  "code": "VALIDATION_FAILED",
  "message": "Validation failed.",
  "errors": {
    "email": "Email is required"
  }
}

Standard Error Codes

CodeHTTP StatusWhen Used
AUTH_REQUIRED401Missing or absent authentication
AUTH_INVALID401Malformed or tampered JWT
TOKEN_EXPIRED401JWT has expired
INSUFFICIENT_PERMISSIONS403User lacks required role/permission
RESOURCE_NOT_FOUND404Invalid MongoDB ObjectId or missing document
DUPLICATE_RESOURCE400Unique constraint violation (e.g., duplicate email)
VALIDATION_FAILED400Mongoose schema or Zod validation failure
INVALID_PAYLOAD400Malformed JSON in request body
RATE_LIMITED429Rate limiter rejection
SERVER_ERROR500Unhandled or unknown error

Frontend Integration

The frontend's Axios interceptor (services/api/client.ts) uses the code field to:

  1. Look up the error in the Error Code Registry (constants/errorCodes.ts)
  2. Determine the severity (error / warning / info)
  3. Route it to the correct UI mechanism (Toast, Banner, Inline Error, or Redirect)
Backend Response → code: "TOKEN_EXPIRED"


Error Code Registry → { title: "Session Expired", severity: "warning", action: "Login" }


Notification Manager → Toast (warning) + Redirect to /login

This means pages never manually interpret HTTP status codes. The API client layer handles it automatically.

On this page