Skip to content

Commit

Permalink
feat(errors): add error class and functions (#113)
Browse files Browse the repository at this point in the history
Signed-off-by: james-a-morris <[email protected]>
Co-authored-by: amateima <[email protected]>
  • Loading branch information
james-a-morris and amateima authored Nov 25, 2024
1 parent e0f8b8d commit 2117af5
Show file tree
Hide file tree
Showing 16 changed files with 280 additions and 45 deletions.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ COPY packages/persistence-example/package.json ./packages/persistence-example/pa
COPY packages/template/package.json ./packages/template/package.json
COPY packages/typescript-config/package.json ./packages/typescript-config/package.json
COPY packages/webhooks/package.json ./packages/webhooks/package.json
COPY packages/error-handling/package.json ./packages/error-handling/package.json

# Build the dependencies into a node_modules folder
RUN pnpm install --frozen-lockfile
Expand Down
10 changes: 10 additions & 0 deletions packages/error-handling/.mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extension": [
"ts"
],
"spec": "**/*.test.ts",
"require": [
"ts-node/register"
],
"recursive": true
}
3 changes: 3 additions & 0 deletions packages/error-handling/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# HTTP Error Handling Module

This module provides a comprehensive system for managing errors within the indexer package. It is meant to be a centralized constants repository for Indexer related errors
6 changes: 6 additions & 0 deletions packages/error-handling/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// .eslintrc.js in the new package
module.exports = {
root:true,
extends: ['@repo/eslint-config/library.js'],
};

46 changes: 46 additions & 0 deletions packages/error-handling/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@repo/error-handling",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc -b",
"build:check": "tsc --noEmit",
"watch": "tsc -b --watch",
"fix": "pnpm format && pnpm lint",
"format": "prettier --write src",
"format:check": "prettier src --check",
"lint": "eslint --fix",
"lint:check": "eslint",
"check": "pnpm format:check && pnpm lint:check && pnpm build:check",
"test": "mocha",
"coverage": "nyc mocha",
"test:watch": "mocha --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"http-status-codes": "^2.3.0"
},
"exports": {
".": "./dist/index.js"
},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@repo/eslint-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@types/chai": "^4.3.17",
"@types/mocha": "^10.0.7",
"@types/node": "^16.11.10",
"chai": "^4.5.0",
"eslint": "^8.57.0",
"mocha": "^10.7.0",
"nyc": "^17.0.0",
"prettier": "^3.3.3",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"winston": "^3.13.1"
}
}
7 changes: 7 additions & 0 deletions packages/error-handling/src/errors/AssertError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IndexerError } from "./IndexerError";

export class AssertError extends IndexerError {
constructor(message: string) {
super(AssertError.name, message);
}
}
25 changes: 25 additions & 0 deletions packages/error-handling/src/errors/IndexerError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Generic Error class that should be used in the Indexer to
* provide common error patterns to log
*/
export abstract class IndexerError extends Error {
constructor(
private readonly errorName: string,
private readonly errorMessage: string,
private readonly errorData?: Record<string, string>,
) {
super(errorMessage);
}

/**
* A function used by `JSON.stringify` to specify which data will be serialized
* @returns A formatted JSON
*/
public toJSON(): Record<string, unknown> {
return {
error: this.errorName,
message: this.errorMessage,
data: this.errorData,
};
}
}
31 changes: 31 additions & 0 deletions packages/error-handling/src/errors/IndexerHTTPError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { StatusCodes } from "http-status-codes";
import { IndexerError } from "./IndexerError";

export { StatusCodes };

/**
* Used to distinguish a similar design pattern as {@link IndexerError} but with
* additional HTTP context
* @see {@link IndexerError}
*/
export abstract class IndexerHTTPError extends IndexerError {
constructor(
private readonly httpStatusCode: StatusCodes,
errorName: string,
errorMessage: string,
errorData?: Record<string, string>,
) {
super(errorName, errorMessage, errorData);
}

/**
* A function used by `JSON.stringify` to specify which data will be serialized
* @returns A formatted JSON
*/
public toJSON(): Record<string, unknown> {
return {
statusCode: this.httpStatusCode,
...super.toJSON(),
};
}
}
3 changes: 3 additions & 0 deletions packages/error-handling/src/errors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./IndexerError";
export * from "./IndexerHTTPError";
export * from "./AssertError";
2 changes: 2 additions & 0 deletions packages/error-handling/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./errors";
export * from "./utils";
31 changes: 31 additions & 0 deletions packages/error-handling/src/main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, it } from "mocha";
import { expect } from "chai";
import assert from "assert";
import { AssertError } from "./errors";
import { isIndexerError, assert as customAssert } from "./utils";

describe("Error handling Tests", function () {
it("should run the toJSON in Stringify", () => {
const e = new AssertError("test");
const jsonStringifyDirectly = JSON.stringify(e.toJSON());
const jsonIndirectly = JSON.stringify(e);
expect(jsonIndirectly).to.eq(jsonStringifyDirectly);
});

describe("typeguards", function () {
it("should validate IndexerError", () => {
const e = new AssertError("test");
expect(isIndexerError(e)).to.be.true;
});
});

describe("utils", () => {
it("should run assert as expected", () => {
expect(() => assert(false, "")).to.throw;
expect(() => customAssert(false, "")).to.throw;

expect(() => assert(true, "")).to.not.throw;
expect(() => customAssert(true, "")).to.not.throw;
});
});
});
17 changes: 17 additions & 0 deletions packages/error-handling/src/utils/assert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as assertModule from "assert";
import { AssertError } from "../errors/AssertError";

/**
* A stand-in assert function that returns a formatted error payload
* @param value An arbitrary predicate that will be asserted for truthiness
* @param message An error message that will be passed if the assert fails
* @returns An assertion of `value`.
* @throws {@link AssertError} if assert's validity fails
*/
export function assert(value: unknown, message: string): asserts value {
try {
return assertModule.ok(value, message);
} catch (e: unknown) {
throw new AssertError(message);
}
}
2 changes: 2 additions & 0 deletions packages/error-handling/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./assert";
export * from "./typeguards";
19 changes: 19 additions & 0 deletions packages/error-handling/src/utils/typeguards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IndexerError, IndexerHTTPError } from "../errors";

/**
* Typeguard to confirm that an object is an IndexerError
* @param error The error object to validate
* @returns Whether this object is an instance of `IndexerError` (or a descendent)
*/
export function isIndexerError(error: unknown): error is IndexerError {
return error instanceof IndexerError;
}

/**
* Typeguard to confirm that an object is an IndexerHTTPError
* @param error The error object to validate
* @returns Whether this object is an instance of `IndexerHTTPError` (or a descendent)
*/
export function isIndexerHTTPError(error: unknown): error is IndexerHTTPError {
return error instanceof IndexerHTTPError;
}
6 changes: 6 additions & 0 deletions packages/error-handling/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends":"@repo/typescript-config/base.json",
"compilerOptions": {
"outDir": "./dist" /* Specify an output folder for all emitted files. */
}
}
Loading

0 comments on commit 2117af5

Please sign in to comment.