# 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://thescottyjam.gitbook.io/explicit-exceptions/master.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
