You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

80 lines
5.6 KiB
Markdown

4 years ago
# error-chain
Finally, a sensible way to deal with error handling in Javascript!
`error-chain` lets you create custom error types, that you can 'chain' to provide more context without losing the original error. It also provides a number of utilities for dealing with these 'chained errors', including tools for filtering error types.
__Work in progress!__ This is an experimental pre-release. All of the utilities are currently packaged into this single package to make iterating on the design easier, but they will eventually become separate packages under the `@error-chain/*` namespace.
While semantic versioning is still followed in principle, and so it should be fine to use this package in production already, it being a pre-release means there's a slightly higher chance of unintended API breakage, the documentation is not complete yet, and there may be bugs or awkward APIs. But if that's still an improvement over what you're currently doing - and for many people it probably will be - you should feel free to use it anyway!
__Library implementers:__ If you use `error-chain` in your library (which you should!), please make sure to describe in the README that you are using it, and link to the below section. That will help your users understand how to work with these sorts of errors. While they *can* be handled like normal `Error` objects, your users will be able to get much more information out of them with the right tools.
## If you are trying to work with or understand a chained error
You may be using a library that uses `error-chain`, and wonder what it's all about. Or maybe you got a pretty vague error, and it *seems* like there should be more information, but it's not quite visible. That's probably because the details are stored in what's called the "cause chain" - the chain of errors that led up to the one you're looking at.
This library provides a number of utilities to get the most out of these errors. These are:
- __getContext(error):__ This is a function that retrieves all of the "context" of every error along the chain, and merges it into a single object for you to use. "Context" is basically all of the custom properties on the errors, like HTTP status codes, protocol-specific error codes, and so on.
- __render(error):__ This is a function that, given an error (from `error-chain` or otherwise), produces a string that describes in detail what went wrong - it includes the original stacktrace from where the first error occurred, as well as a list of all the other errors in the chain, if any, to provide more context. For example, the source error may be "unable to open file", and a higher-level error might explain that this resulted in a failure to load the configuration. Note that this __does not__, by itself, log anything to the console - it just creates a string that you can log yourself, anywhere you want.
- __getChain(error):__ If you'd rather generate your own error display, or otherwise want to deal with the chain of errors, this function will give you the entire chain behind an error as an array, ordered from highest-level to lowest-level (source) error.
- __match(rules):__ If you're trying to write error handling code that only handles specific errors (which you should!), you can use this function to produce a 'filter' for them, based on your own rules - which get applied *to any error in the chain*. This means that if you try to `match(CustomErrorType)` for example, that will not only match top-level errors of the `CustomErrorType`, but any error that has a `CustomErrorType`-error *anywhere in its chain*. The API is explained more below.
- ... list to be completed ...
## API
### create(name, [options])
To be documented.
### match(rules)
Given one or more `rules`, this function will generate and return a so-called "predicate function" - ie. a function that takes an error as its argument, and then returns `true` or `false` depending on whether it matched. The `rules` are applied to every error in the chain, not just the top-level one - and if any of them matches, the predicate returns `true`.
In practice, you'll probably use this combined with something like Bluebird's `catch` filtering feature:
```js
doSomething().catch(match(HTTPError), (error) => /* ... */)
```
The `rules` themselves can be one of the following kinds of values:
- __An error type (constructor function or class):__ In this case, it will use `instanceof` on each error in the chain, to determine whether it's a match.
- __An object of properties:__ In this case, it will compare each error in the chain against the object, and consider it a match when all the (rule) properties match against the error. Only one error in the chain needs to match, but *all* of the properties need to match (excluding ones not specified in the rule).
- __A function:__ In this case, it will run the function *for each error in the chain*, and consider it a match if it returns `true` for any of them.
You can also specify *multiple* values in the `rules`, like so:
```js
match([ CustomErrorType, { errorCode: "OH_NO" } ])
```
In that case, an error will only be considered a match if *all* of the rules match against it, on the same error in the chain.
### is(error, rules)
Like `match(rules)`, but instead of creating a predicate function, it directly returns `true` or `false`. Useful if you want to manually check the error type/shape.
### rethrowAs(errorType, ... arguments)
To be documented.
### chain(error, errorType, ... arguments)
To be documented.
### getContext(error)
To be documented.
<!-- FIXME: Make sure to mention merge precedence -->
### getChain(error)
To be documented.
### render(error)
To be documented.