import autoBind from 'auto-bind'; import Err from 'err'; import HTTP_STATUS from 'http-status'; import log from '@/logger'; interface ServiceInterface { responseBuilder: any; } /** * @class */ export class ExceptionHandler { readonly services: ServiceInterface; /** * @param {object} services * @param {object} config * @param {boolean} [doAutoBind=true] */ constructor(services: ServiceInterface, config?, doAutoBind = true) { this.services = services; if (doAutoBind) { autoBind(this); } } /** * Express middleware for json body parser errors. * From here: {@link https://github.com/expressjs/body-parser/issues/122#issuecomment-328190379} * * @param {Error|RError|object} error unhandled error * @param {Request} request express request * @param {Response} response express response * @param {Function} next * @returns {Promise<void>} */ async handleJsonParseError(error, request, response, next): Promise<void> { if (error.type && error.type === 'entity.parse.failed') { await this.services.responseBuilder.respond(response, new Err('Could not parse JSON input', HTTP_STATUS.BAD_REQUEST, error.body)); return; } next(error); } /** * Express middleware for catching unhandled errors and returning a 500 * * @param {Error|RError|object} error unhandled error * @param {Request} request express request * @param {Response} response express response * @param {Function} next * @returns {Promise<void>} */ async handleError(error, request, response, next): Promise<void> { // If the error object doesn't exist if (!error) { next(); return; } if (error.stack) { log.error(`Unhandled error: ${error.stack}`); } else { log.error(`Unhandled error without stack: ${JSON.stringify(error)}`); } await this.services.responseBuilder.respond(response, new Err('Unhandled error occurred', HTTP_STATUS.INTERNAL_SERVER_ERROR)); } /** * Express middleware for catching all unhandled requests and returning 404 * * @param {Request} request express request * @param {Response} response express response * @returns {Promise<void>} */ async handleNotFound(request, response): Promise<void> { const url = request.originalUrl; const { method } = request; await this.services.responseBuilder.respond(response, new Err(`URL: ${url} with method: ${method} is not a valid path`, HTTP_STATUS.NOT_FOUND)); } }