diff --git a/packages/indexer-api/src/error-handler.ts b/packages/indexer-api/src/error-handler.ts new file mode 100644 index 0000000..ee00a56 --- /dev/null +++ b/packages/indexer-api/src/error-handler.ts @@ -0,0 +1,45 @@ +import { + isIndexerError, + isIndexerHTTPError, + StatusCodes, +} from "@repo/error-handling"; +import { Request, Response, NextFunction } from "express"; +import { isHttpError } from "./express-app"; +import { StructError } from "superstruct"; + +const DEFAULT_STATUS = StatusCodes.BAD_REQUEST; + +const errorHandler = ( + err: unknown, + req: Request, + res: Response, + _: NextFunction, +): void => { + // At a base level we need to confirm that this isn't a valid + // passthrough - if so ignore + if (isIndexerError(err)) { + // If we have a custom sub-type to specify the error code, use it + // otherwise default to a status 400 + const httpStatus = isIndexerHTTPError(err) + ? err.httpStatusCode + : DEFAULT_STATUS; + res.status(httpStatus).json(err.toJSON()); + } else if (isHttpError(err)) { + res.status(err.status ?? DEFAULT_STATUS).json({ + message: err.message, + error: "NavigationError", + }); + } else if (err instanceof StructError) { + res.status(StatusCodes.BAD_REQUEST).json({ + error: "InputValidationError", + message: err.message, + }); + } else if (err instanceof Error) { + res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ + error: "UnknownError", + message: err.message, + }); + } +}; + +export default errorHandler; diff --git a/packages/indexer-api/src/express-app.ts b/packages/indexer-api/src/express-app.ts index 21b47b0..b07a511 100644 --- a/packages/indexer-api/src/express-app.ts +++ b/packages/indexer-api/src/express-app.ts @@ -2,6 +2,7 @@ import cors from "cors"; import bodyParser from "body-parser"; import type { Request, Response, NextFunction, Express, Router } from "express"; import express from "express"; +import errorHandler from "./error-handler"; export class HttpError extends Error { status?: number; @@ -31,33 +32,14 @@ export function ExpressApp(routers: RouterConfigs): Express { }); app.use(function (_: Request, __: Response, next: NextFunction) { - const error = new HttpError("Not Found"); + const error = new HttpError("Route does not exist."); error["status"] = 404; next(error); }); - app.use(function ( - err: HttpError | Error, - req: Request, - res: Response, - // this needs to be included even if unused, since 4 param call triggers error handler - _: NextFunction, - ) { - const request = { - method: req.method, - path: req.path, - body: req.body, - }; - let status = 500; - if (isHttpError(err)) { - status = err.status ?? status; - } - res.status(status).json({ - message: err.message, - request, - stack: err.stack, - }); - }); + // Register an error handler as the last part of the + // express pipeline + app.use(errorHandler); return app; } diff --git a/packages/indexer-api/src/services/exceptions.ts b/packages/indexer-api/src/services/exceptions.ts index 621c257..1982996 100644 --- a/packages/indexer-api/src/services/exceptions.ts +++ b/packages/indexer-api/src/services/exceptions.ts @@ -1,18 +1,17 @@ -import { HttpError } from "../express-app"; -import { HttpStatus } from "../model/httpStatus"; +import { IndexerHTTPError, StatusCodes } from "@repo/error-handling"; -export class DepositNotFoundException extends HttpError { +export class DepositNotFoundException extends IndexerHTTPError { constructor() { - super("Deposit not found"); - this.name = "DepositNotFoundException"; - this.status = HttpStatus.NOT_FOUND; + super( + StatusCodes.NOT_FOUND, + DepositNotFoundException.name, + "Deposit not found given the provided constraints", + ); } } -export class IndexParamOutOfRangeException extends HttpError { +export class IndexParamOutOfRangeException extends IndexerHTTPError { constructor(message: string) { - super(message); - this.name = "IndexParamOutOfRangeException"; - this.status = HttpStatus.BAD_REQUEST; + super(StatusCodes.BAD_REQUEST, IndexParamOutOfRangeException.name, message); } }