2

How should I throw Exceptions the correct way so that I dont lose any information?

Consider this example:

try {
  this.stripe.customers.create({ ... });
} catch(e) {
  throw new MyCustomCreateCustomersException();
}

In this case I can see in my logs that MyCustomCreateCustomersException was thrown and where. But that stack trace does not include anything about whatever Stripe thrown, so the real error is lost here.

It is kind of obvious I guess since I left out e and did not use it, but I am unsure about what is the best way of using it? I would like to have custom exceptions as well, that seems to be a good practice, but I don't want to lose any information deeper down.

MyCustomCreateCustomersException is inheriting from Error.

rablentain
  • 6,641
  • 13
  • 50
  • 91
  • 1
    Possible duplicate of [Re-throwing exception in NodeJS and not losing stack trace](https://stackoverflow.com/questions/42754270/re-throwing-exception-in-nodejs-and-not-losing-stack-trace) – MauriceNino Oct 22 '19 at 07:33

1 Answers1

0

What I am proposing here is instead of using classes use functions which will create wanted error structures. So we will not loose any information from the original error, but we can also add some metadata to represent special type of error. Consider

  // we are copying orginal error to not loose the data:
const createCustomerError = (e: Error) => ({...e, errorType: 'CREATE_CUSTOMER'});
const otherError = (e: Error) => ({...e, errorType: 'OTHER'});

Thanks to that you have the stacktrace, message but also additional information. You can add whenever metadata you want. Nice would be also to model such errors in type:

type ErrorType = 'CREATE_CUSTOMER' | 'OTHER' // can be also enum
type MyError = {errorType: ErrorType } & Error;

// also we should define our error function output as MyError:
const createCustomerError = (e: Error): MyError => ({...e, errorType: 'CREATE_CUSTOMER'});
const otherError = (e: Error): MyError => ({...e, errorType: 'OTHER'});

Thanks to that type you can make a handler with standard switch/if to handle specific errors like:

// some parent handler which will handle those re thrown errors
switch(error.errorType) {
  case 'CREATE_CUSTOMER': 
     someHandler();
     break;
  case 'OTHER': 
     someHandler2();
     break;
  default:
     defaultErrrorHandler();
}

Last but not least. Using function error constructors looks like:

try {
  this.stripe.customers.create({ ... });
} catch(e) {
  throw createCustomerError(e);
}
Maciej Sikora
  • 19,374
  • 4
  • 49
  • 50