Git Product home page Git Product logo

catch-decorator-ts's Introduction

Catch Decorator TS

Description

Typescript decorator for handling your exceptions elegantly.


Install

npm install catch-decorator-ts

If you use Typescript enable experimentalDecorators flag inside your tsconfig file, otherwise for babel use one of the following plugins babel-plugin-transform-decorators-legacy or @babel/plugin-proposal-decorators.


Usage

Writing code that correctly handles all kinds of errors is hard. Developers usually wrap methods with try/catch block in order to handle different kinds of errors. Now imagine as number of anticipated errors increases, it would mess out with the codebase readability, right? That's why it feels natural to use decorators in order to separate method logic from error handling logic.

// Handler for `Catch` or `DefaultCatch` decorators
// err - error thrown from decorated method
// context - `this` value from decorated method
// args - spreaded arguments from decorated method
type Handler = (err: any, context: any, ...args: any) => any;

// Handler will be executed if decorated method has thrown an error which is instance of `ErrorClassConstructor`
@Catch(ErrorClassConstructor: Function, handler: Handler)

// Handler will be executed no matter what type of error has been thrown
@DefaultCatch: (handler: Handler)

Consider the following example:

class User {
  private repository;

  async getUser(id) {
    try {
      const user = await this.repository.fetch(id);
      return user;
    } catch (error) {
      if (error instanceof DatabaseError) {
        console.log('DatabaseError');
      } else if (error instanceof ConnectionError) {
        console.log('ConnectionError');
      } else {
        console.log('UnrecognizedError');
      }
    }
  }
}

Now let's rewrite the previous example using the introduced decorator. Code remains semantically the same, but more clear for other developers to read it.

import { Catch, DefaultCatch } from 'catch-decorator';

class User {
  private repository;

  constructor() {
    this.getUser = this.getUser.bind(this);
  }

  @DefaultCatch((err, ctx, id) => console.log('UnrecognizedError'))
  @Catch(ConnectionError, (err, ctx, id) => console.log('ConnectionError'))
  @Catch(DatabaseError, (err, ctx, id) => console.log('DatabaseError'))
  async getUser(id) {
    const user = await this.repository.fetch(id);
    return user;
  }
}

Remember when stacking decorators that their execution is going to happen in reverse order.

@DefaultCatch(quxHandler)
@Catch(Foo, fooHandler)
@Catch(Bar, barHandler)
@Catch(Baz, bazHandler)
someRandomMethod(){
  throw new QuxError("oops");
}

Which means that the handlers above are going to execute in following order:

bazHandler -> barHandler -> fooHandler -> quxHandler

Also, it is required to put the DefaultCatch decorator at the very top, otherwise all the Catch decorators above him are not going to get executed as the handler from DefaultCatch will be called nevertheless of the error type. Of course, decorating method with DefaultCatch is optional.

It is also possible to define error handlers as external variables or bind them as class's static methods.

import { Catch, DefaultCatch, Handler } from 'catch-decorator';

const connectionErrorHandler: Handler = (err, ctx, id) =>
  console.log('ConnectionError');
const databaseErrorHandler: Handler = (err, ctx, id) =>
  console.log('DatabaseError');

class User {
  private repository;

  constructor() {
    this.getUser = this.getUser.bind(this);
  }

  @DefaultCatch(User.defaultErrorHandler)
  @Catch(ConnectionError, connectionErrorHandler)
  @Catch(DatabaseError, databaseErrorHandler)
  async getUser(id) {
    const user = await this.repository.fetch(id);
    return user;
  }

  static defaultErrorHandler: Handler = (err, ctx, id) =>
    console.log('UnrecognizedError');
}

Example use case with Express.js

Passing express middleware parameters to error handler.

import { Catch, DefaultCatch, Handler } from 'catch-decorator';

const defaultErrorHandler: Handler = (err, ctx, req, res, next, id) =>
  next(err);
const databaseErrorHandler: Handler = (err, ctx, req, res, next, id) =>
  res.send({ error: err });

class UserController {
  private repository;

  constructor() {
    this.load = this.load.bind(this);
  }

  @DefaultCatch(defaultErrorHandler)
  @Catch(DatabaseError, databaseErrorHandler)
  async load(req: Request, res: Response, next: NextFunction, id: string) {
    const user = await this.userRepository.fetch(id);
    res.send({ user });
  }
}

Or if error handler is reused across multiple methods we can write something like this:

import { Catch, DefaultCatch, Handler } from 'catch-decorator';

const TryCatch = () =>
  DefaultCatch((err, ctx, req, res, next, id) => {
    res.send({ error: err });
    // or
    next(err);
  });

class UserController {
  private repository;

  constructor() {
    this.load = this.load.bind(this);
  }

  @TryCatch()
  async load(req: Request, res: Response, next: NextFunction, id: string) {
    const user = await this.userRepository.fetch(id);
    res.send({ user });
  }
}

catch-decorator-ts's People

Contributors

valjic1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

rhzs liuqiang1357

catch-decorator-ts's Issues

No `dist` files since 0.0.3

Hello @valjic1, it seems that since the upgrade to 0.0.3 the project does not export .js files in the dist folder anymore.
For instance, we used to rely on catch-decorator-ts/dist/index.es.js to be available in node_modules, but it's not there anymore.
Is this expected or is it a bug?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.