@leyyo/exception
TypeScript icon, indicating that this package has built-in type declarations

1.0.5 • Public • Published

exception

Abstract Exception/Error for JavaScript/TypeScript

Leyyo > Exception

  • Dynamic/extendable extention for JavaScript/TypeScript
  • Supports supports params
  • Supports cause or previous error, expecially re-triggered errors in try/catch
  • Support parsed stach-trace as array of {file: string, method: string, line: number, arguments: Array};

Aim

  • Standardized Exception structure
  • Easy Monitoring
  • Decrease to figure out errors
  • Modern exception logging

TODO

  • [ ] I18N dictionary
  • [x] Logger binding
  • [ ] API response supports
  • [ ] Severity usage
  • [ ] Environment based usage
  • [ ] Triggers (email, sms, slack etc)

Install

npm i @leyyo/exception

Standards

  • [x] Language: TS
  • [x] Eslint: Yes
  • [x] Static Code Analysis: Yes IntelliJ Code Inspections
  • [x] DDD - Document Driven: No
  • [x] EDD - Exception Driven: Yes
  • [ ] TDD - Test Driven: Yes go to test folder

Commands

  • npm run clear // clears "dist" folder
  • npm run lint // runs eslint for static code analysis
  • npm run build // builds JS files at "dist" folder
  • npm run test // runs test files in "test" folder
  • npm run test:watch *// runs test with watch option
  • npm run test:coverage *// runs test with coverage

Assumption

  • Your company name is 'Lemonade'

Basic Sample

Define Your Named Exception

// file: DbConnectionException.ts
import {Exception} from "@leyyo/exception";

@Fqn('lemonade')
export class DbConnectionException extends Exception {
    constructor(type: string, host: string) {
        super(`Database[${type}] could not connect to host: "${host}"`, {type, path});
    }
}

Base Exception

// file: MongoConnect.ts --sample
import {DbConnectionException} from "./DbConnectionException";

// ....
throw new DbConnectionException('mongodb', 'mongo.44444.aws.com');

It generates ...

{
  "name": "lemonade.DbConnectionException",
  "message": "Database[mongodb] could not connect to host: \"mongo.44444.aws.com\"",
  "params": {
    "type": "mongodb",
    "host": "mongo.44444.aws.com"
  }
}

With Chained Exception

import {DbConnectionException} from "./DbConnectionException";

const host = 'mongo.44444.aws.com';
try {
    await mongodb.connect(host, 27017, 'user', 'pa55w0rd'); // fake code :)
} catch (e) { // assume that e is instance of MongoNetworkError
    throw new DbConnectionException('mongodb', host).withCause(e); // append previous error to raised error
}

It generates ...

{
  "name": "lemonade.DbConnectionException",
  "message": "Database[mongodb] could not connect to host: \"mongo.44444.aws.com\"",
  "params": {
    "type": "mongodb",
    "host": "mongo.44444.aws.com"
  },
  "cause": {
    "name": "MongoNetworkError",
    "message": "failed to connect to server [mongo.44444.aws.com:27017] on first connect"
  }
}

With Error Trace

import {DbConnectionException} from "./DbConnectionException";

const host = 'mongo.44444.aws.com';
try {
    await mongodb.connect(host, 27017, 'user', 'pa55w0rd'); // fake code :)
} catch (e) { // assume that e is instance of MongoNetworkError
    throw new DbConnectionException('mongodb', host).withCause(e).withStack(); // parses native e.stack
}

It generates ...

{
  "name": "lemonade.DbConnectionException",
  "message": "Database[mongodb] could not connect to host: \"mongo.44444.aws.com\"",
  "params": {
    "type": "mongodb",
    "host": "mongo.44444.aws.com"
  },
  "cause": {
    "name": "MongoNetworkError",
    "message": "failed to connect to server [mongo.44444.aws.com:27017] on first connect"
  },
  "parsedStack": [
    {
      "file": "... file path, @look errorUtils.folder",
      "method": "function or method name[if in class]",
      "line": "line number",
      "arguments": ["foo", 5]
    }
  ]
}

Http Sample

Define Your Named Exception

// file: DbConnectionException.ts
import {HttpException} from "@leyyo/exception";

// HttpException is inherited from Exception
// It supports also with withCause and withStack builder methods
// there is only a difference, you set status property, so you can use it for API responses

@Fqn('lemonade')
export class NotFoundRecordException extends HttpException {
    constructor(entity: string, id: string | number) {
        super(`Record of ${entity} could not be found with id: "${id}"`, 404, {entity, id});
    }
}

Usage

// file: NotFoundRecordException.ts --sample
import {NotFoundRecordException} from "./NotFoundRecordException";

// ....
throw new NotFoundRecordException('Customer', 6666);

It generates ...

{
  "name": "lemonade.NotFoundRecordException",
  "message": "Record of Customer could not be found with id: \"6666\"",
  "params": {
    "entity": "Customer",
    "id": 6666
  },
  "status": 404
}


Your Custom Abstract Exception

Define Your Named Exception

import {Exception} from "@leyyo/exception";

// you may need your custom abstract error class and you need to inherit all named exception from it
// We assume that you need two properties for all exceptions, and they are environment and micro-service
// there is only a difference, you set status property, so you can use it for API responses

@Fqn('<your.company.package>')
export abstract class LemonadeException extends Exception {
    readonly environment: string = process.env.NODE_ENV;
    readonly microservice: string = 'notification-api';
    protected constructor(message: string, params?: Record<string, unknown>) {
        super(message, params);
    }
}

A named exception as a sample

// file: DbConnectionException.ts
import {LemonadeException} from "./LemonadeException";

@Fqn('lemonade')
export class DbConnectionException extends LemonadeException {
    constructor(type: string, host: string) {
        super(`Database[${type}] could not connect to host: "${host}"`, {type, path});
    }
}

It generates ...

{
  "name": "lemonade.DbConnectionException",
  "message": "Database[mongodb] could not connect to host: \"mongo.44444.aws.com\"",
  "params": {
    "type": "mongodb",
    "host": "mongo.44444.aws.com"
  },
  "environment": "prod",
  "microservice": "notification-api"
}

A named Http exception as a sample

import {HttpException} from "@leyyo/exception";

// And also you may need your custom http exception
@Fqn('lemonade')
export abstract class LemonadeHttpException extends HttpException {
    readonly environment: string = process.env.NODE_ENV;
    readonly microservice: string = 'notification-api';
    protected constructor(message: string, status?: number, params?: Record<string, unknown>) {
        super(message, number, params);
    }
}

It generates ...

{
  "name": "lemonade.NotFoundRecordException",
  "message": "Record of Customer could not be found with id: \"6666\"",
  "params": {
    "entity": "Customer",
    "id": 6666
  },
  "status": 404,
  "environment": "prod",
  "microservice": "notification-api"
}

Settings

import {exceptionOptions} from "@leyyo/exception";

exceptionOptions
    .setLambda((err) => {}) // Function for error log
    .setI18nLambda((err, req) => {}) // Function for building I18N
    .setStatus((err) => {}) // it should be integer between 400 - 999, else default is 400

;

Author

Package Sidebar

Install

npm i @leyyo/exception

Weekly Downloads

2

Version

1.0.5

License

ISC

Unpacked Size

21.6 kB

Total Files

15

Last publish

Collaborators

  • erdibuyuk
  • mustafayelmer