'use strict'; const { MulterError } = require("multer"), { ValidationError } = require("joi"), { Errors, LIMIT_FILE_SIZE_ERR } = require('../helpers/constants'), { AppError, AppAuthError } = require("../helpers/app_error"), env = require('../helpers/env'), utils = require('../helpers/utils'), debug = require('debug')('agm:errHandler'); function createAppErrObj(tag = Errors.UNKNOWN_APP_ERROR) { return { error: { '.tag': tag } }; } function createAppValidationErrObj(valError) { let errObj = createAppErrObj(Errors.INVALID_PARAM); if (!utils.isEmptyObj(valError) && valError.message) { errObj.error.message = valError.message; } return errObj; } /** * Handle Application error for a given request with the provided error object * @param {*} req The Request object of the request * @param {*} res The Response object of the request * @param {*} err The error object (runtime error object or App* error classes) * Notes: return HTTP statusCode for the custom App errors with 409 as default. * For Stripe errors the code will always be 402. The client should base on the .code value for detail error. * @returns */ function ErrorHandler(err, req, res, next) { const statusCode = err && err.statusCode || 409; // Application error default HTTP status code try { if (err.type && err.type.startsWith('Stripe')) { /* For Stripe errors the code will always be 402. The client should base on the .code value for detailed error. TODO: In Production mode => consider filtering Stripe errors to send back less detail. */ return res.status(402).send(err); } // Handle Joi ValidationError if (err instanceof ValidationError) { return res.status(statusCode).send(createAppValidationErrObj(err)); } // Handle Mongoose ValidationError as AppParamError if (err.name === 'ValidationError') { // const messages = Object.values(err.errors).map((e) => e.message).join(', '); return res.status(409).send(createAppValidationErrObj(err)); } if (err instanceof AppError) { return res.status(err.statusCode).send(createAppErrObj(err.message)); } // Handle Mongoose duplicate key error (e.g., unique index violation) if (typeof err === "object" && err.code === 11000) { return res.status(statusCode).send(createAppErrObj(Errors.DUPLICATED_VALUE)); } // Handle Multer file upload errors if (err instanceof MulterError) { return res.status(statusCode).send(createAppErrObj(err.code == LIMIT_FILE_SIZE_ERR ? Errors.FILE_TOO_LARGE : Errors.INVALID_PARAM)); } // Handle unknown errors res.status(500).send(createAppErrObj(Errors.UNKNOWN_ERROR)); } catch (error) { res.status(500).send(createAppErrObj(Errors.UNKNOWN_APP_ERROR)); } finally { env.LOG_ALL_ERRORS && (debug(err instanceof AppAuthError ? err.message : err)); } } module.exports = { ErrorHandler }