All files / ragchat-api/utils handleErrors.js

84.74% Statements 100/118
88.23% Branches 15/17
80% Functions 4/5
84.74% Lines 100/118

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 1191x 1x 1x 1x 1x 27x 27x 27x 27x 27x 27x 27x 1x 1x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 5x 5x 8x 8x 3x 3x 8x 8x 1x 1x 1x 1x 1x 27x 27x 27x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 27x 27x 19x 19x 19x 19x 19x 45x 45x 45x 45x 45x                         45x 45x 19x 19x 19x 19x 19x 19x 19x 27x 27x 6x 6x     6x 6x 6x 6x 6x 27x 27x 1x 1x 1x 1x 1x         1x 1x 1x 1x 1x 27x 27x 27x 27x 27x 27x 27x 27x  
/**
 * Return extended error incl. statuscode, describing message and optional messages
 */
export class CustomError extends Error {
  constructor(error) {
    super(error.message);
    this.name = error.name;
    this.statusCode = error.statusCode || generateErrorStatusCode(error);
    this.body = generateErrorBody(error);
    this.isOperatinal = true;
    Error.captureStackTrace(this, this.constructor);
  }
}
 
/**
 * generate status codes by error names
 */
const generateErrorStatusCode = (error) => {
  switch (error.name) {
    // VALIDATION ERROR
    case "ValidationError":
    case "JsonWebTokenError":
    // ZOD VALIDATION ERROR
    case "zodError": {
      return 400;
    }
    // DEFAULT ERROR
    default: {
      return 500;
    }
  }
};
 
/**
 * create and return a individual error body
 */
const generateErrorBody = (error) => {
  switch (error.name) {
    // MONGOOSE VALIDATION ERROR
    case "ValidationError": {
      let validationErrors = {};
      Object.keys(error.errors).forEach((key) => {
        validationErrors[key] = error.errors[key].message;
      });
      // return error body
      return {
        message: 'Validation errors. Please check the error messages.',
        validationErrors
      };
    }
    // ZOD VALIDATION ERROR
    case "zodError": {
      let formattedErrors = error.format();
      // prepare object of all validation messages
      let validationErrors = {};
      // loop through all fields
      Object.keys(formattedErrors).forEach((key) => {
        // store field errors into messages
        const messages = formattedErrors[key]._errors;
 
        // if there are subkeys besides _errors
        if (Object.keys(formattedErrors[key]).length > 1) {
          // loop through subkeys 
          Object.keys(formattedErrors[key]).forEach((subkey) => {
            // skip _errors, as it's handled above
            if (subkey === "_errors") return;
            // skip undefined
            if (formattedErrors[key][subkey] == undefined) return;
            // get entry number which throws the error
            const entry = parseInt(subkey) + 1;
            // add subkey to messages
            messages.push(`Entry ${entry}: ${formattedErrors[key][subkey]._errors}`);
          });
        }
        // store messages in validationErrors
        if (messages !== undefined) validationErrors[key] = messages.join();
      });
      // return error body
      return {
        message: 'Validation errors. Please check the error messages.',
        validationErrors
      };
    }
    // DEFAULT ERROR
    default: {
      switch (error.statusCode) {
        case 405:
          // insufficient rights
          return { message: 'Operation not permitted. Insufficient access rights.' };
        default:
          // OTHER ERROR
          return { message: error.message };
      }
    }
  }
};
 
/**
 * used as middleware in router to fetch unknown routes
 */
export const middlewareUnknownRoute = (req, res, next) => {
  const error = new Error(`Route ${req.originalUrl} not found`);
  error.statusCode = 404;
  next(error);
};
 
/**
 * used as middleware in router to fetch and return errors
 */
export const middlewareErrorHandler = (error, req, res, next) => {
 
  // console.error("🚀 ~ middlewareErrorHandler ~ error:", error);
  console.error("🚀 ~ middlewareErrorHandler ~ error:", JSON.stringify(error));
 
  const customError = new CustomError(error);
  // return error to user
  res.status(customError.statusCode).json(customError.body);
};