> For the complete documentation index, see [llms.txt](https://thescottyjam.gitbook.io/explicit-exceptions/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://thescottyjam.gitbook.io/explicit-exceptions/master.md).

# The Big Picture

### How it all fits together

The explicit-exceptions package provides stability to your project by allowing you to explicitly specify which exceptions a function call may provide, each step of the way.

In the [README](https://github.com/theScottyJam/explicit-exceptions), we presented the following example:

```javascript
const { Exception, wrap, unwrap } = require('explicit-exceptions')

const data = new Map()

const getEntry = wrap(id => {
  if (!data.has(id)) {
    // Throws our custom Exception instance, with the intention that
    // our caller would be able to catch and handle this.
    throw new Exception('NotFound')
  }
  return data.get(id)
})

const getEntryOrDefault = (id, defaultValue=null) => {
  try {
    // This line showcases the most important feature of this package.
    // unwrap() self-documents the fact that getEntity() can provide the "NotFound" exception.
    // Runtime checks will ensure no other exceptions leak through that aren't explicitly named here.
    return unwrap(getEntry(id), ['NotFound'])
  } catch (ex) {
    if (!(ex instanceof Exception)) throw ex // Not an exception, don't handle it
    console.assert(ex.code === 'NotFound')
    return defaultValue
  }
}
```

Let's pick this apart and learn what each piece is doing.

```javascript
throw new Exception('NotFound')
```

Exceptions are designed to be easy to distinguish from one another. In this case, this instance can be distinguished from other exceptions by checking if its `code` property equals `"NotFound"`.

Only throw exceptions if you want the caller to be able to recover from it - if you've detected a programmer error (like you found yourself in an invalid state), then throw an instance of `Error()` instead and let your program "crash early".

Any function that can throw instances of Exception should be decorated by `wrap()`.

```javascript
const getEntry = wrap(id => {
  ...
})
```

`wrap()` will take a function and return a new one that captures any thrown exceptions or returned values, and wraps them into a Maybe instance.

{% hint style="info" %}
**Pro tip:** If you want your wrapped function to have a name in error stack traces, you'll have to explicitly give it one like this:

```javascript
const getEntry = wrap(function getEntry(id) {
  ...
})
```

{% endhint %}

`Maybe` instances can only be retrieved from wrapped functions. They're designed to be a black box that holds the result of a wrapped function call. The only thing you can do with the `Maybe` instance is unwrap it (with `unwrap()`). In fact, the library will attempt to detect and warn you if you've forgotten to call `unwrap()` on a `Maybe` instance.

```javascript
return unwrap(getEntry(id), ['NotFound'])
```

Here, `getEntry()` is a wrapped function that will return a `Maybe` instance. This Maybe instance holds details about how getEntry()'s inner function behaved during execution. `unwrap()` will cause one of the following three actions to be performed:

* If `getEntry()` inner function did not throw an exception during its execution, then `unwrap()` will simply return whatever getEntry() inner function returned.
* If `getEntry()`'s inner function threw a `NotFound` exception, then unwrap will cause it to be rethrown, because we've declared that we expected it in the second parameter to unwrap.
* If `getEntry()` were to throw a different `NotAvailable` exception that was not found in our list of expected exceptions, then unwrap will instead throw an instance of `Error()` explaining that a programmer error has occured. This is called "escalating" the exception.

Note that it's ok, and even encouraged to have unwrap's expected-exceptions parameter not be an exhaustive list of exceptions that the wrapped function can provide. If you have no way of handling the exception, then omit it from the expected-exception list, and let it escalate.

```javascript
const getEntryOrDefault = (id, defaultValue=null) => {
  try {
    return unwrap(getEntry(id), ['NotFound'])
  } catch (ex) {
    // ...
  }
}
```

Notice that getEntryOrDefault isn't getting wrapped with `wrap()`. This is because the only exception being thrown inside (`NotFound`) is also getting handled before reaching its caller.

### interoperability with other exception systems

You may wish to have explicit-exceptions be an internal detail to your package, and keep your package users unaware of its use. [This](/explicit-exceptions/exception-system-interoperability.md) dedicated page explains how to achieve this.

### Next Steps

Check out the [API Reference](/explicit-exceptions/api-reference.md) to learn more about the finer details of each function. Or, go ahead and give it an install with `npm i explicit-exceptions`. You may also be interested in the [light version](https://gist.github.com/theScottyJam/fee1a93db153d87fbbf3d45fc0241c49), which provides a simplified variation of this project, intended for those who would prefer maintaining around 100 lines of code themself instead of adding a new dependency to their project.
