UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

72 lines (63 loc) 2.05 kB
import type { ErrorRequestHandler, NextFunction, Request, Response, } from 'express'; import type { ResponseError, Services } from '../../typings'; import statusCodes from 'http-status-codes'; export function errorHandler(services: Services): ErrorRequestHandler { /** * Note: the last argument `next` is important because if its not present, the function * will not be called at all. */ return ( err: ResponseError, _req: Request, res: Response, _next: NextFunction, ): void => { if (typeof err !== 'object') { // If the object is not an Error, create a representation that appears to be err = { name: 'Internal Server Error', // eslint-disable-line no-param-reassign status: statusCodes.INTERNAL_SERVER_ERROR, message: String(err), // Coerce to string }; } else { // Ensure that err.message is enumerable (It is not by default) Object.defineProperty(err, 'message', { enumerable: true }); Object.defineProperty(err, 'status', { enumerable: true, value: err.status || statusCodes.INTERNAL_SERVER_ERROR, }); } if (err.status === statusCodes.INTERNAL_SERVER_ERROR) { services.telemetry.logger.error( '[Express#ErrorHandler] Internal server error', err, ); } const errorBody = { message: err.message, status: err.status, details: err.details ?? [], }; // If we have a server error, then we need to obfuscate its details in the // response. if (err.status === statusCodes.INTERNAL_SERVER_ERROR) { services.telemetry.logger.error( '[Express#ErrorHandler] Internal Server Error', { err }, ); errorBody.message = 'Internal Server Error'; } services.telemetry.logger.debug('[Express#ErrorHandler] Error response', { errorBody, }); res.locals.meter && res.locals.meter({ state: err.status, ...res.locals.attributes }); res.status(err.status!).json(errorBody); }; }