Skip to content
Merged
72 changes: 68 additions & 4 deletions doc/error_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ error-handling for C++ exceptions and JavaScript exceptions.
The following sections explain the approach for each case:

- [Handling Errors With C++ Exceptions](#exceptions)
- [Handling Errors With Maybe Type and C++ Exceptions Disabled](#noexceptions-maybe)
- [Handling Errors Without C++ Exceptions](#noexceptions)

<a name="exceptions"></a>
Expand Down Expand Up @@ -70,7 +71,7 @@ when returning to JavaScript.
### Propagating a Node-API C++ exception

```cpp
Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
Napi::Function jsFunctionThatThrows = someValue.As<Napi::Function>();
Napi::Value result = jsFunctionThatThrows({ arg1, arg2 });
// other C++ statements
// ...
Expand All @@ -84,7 +85,7 @@ a JavaScript exception when returning to JavaScript.
### Handling a Node-API C++ exception

```cpp
Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
Napi::Function jsFunctionThatThrows = someValue.As<Napi::Function>();
Napi::Value result;
try {
result = jsFunctionThatThrows({ arg1, arg2 });
Expand All @@ -96,6 +97,69 @@ try {
Since the exception was caught here, it will not be propagated as a JavaScript
exception.

<a name="noexceptions-maybe"></a>

## Handling Errors With Maybe Type and C++ Exceptions Disabled

If C++ exceptions are disabled (for more info see: [Setup](setup.md)), then the
`Napi::Error` class does not extend `std::exception`. This means that any calls to
node-addon-api function do not throw a C++ exceptions. Instead, these node-api
Comment thread
legendecas marked this conversation as resolved.
Outdated
functions that calling into JavaScript are returning with `Maybe` boxed values.
Comment thread
legendecas marked this conversation as resolved.
Outdated
In that case, the calling side should convert the `Maybe` boxed values with
checks to ensure that the call did succeed and therefore no exception is pending.
If the check fails, that is to say, the returning value is _empty_, the calling
side should determine what to do with `env.GetAndClearPendingException()` before
attempting to calling into another node-api (for more info see: [Env](env.md)).
Comment thread
legendecas marked this conversation as resolved.
Outdated

The conversion from `Maybe` boxed values to actual return value is enforced by
Comment thread
legendecas marked this conversation as resolved.
Outdated
compilers so that the exceptions must be properly handled before continuing.

## Examples with Maybe Type and C++ exceptions disabled

### Throwing a JS exception

```cpp
Napi::Env env = ...
Napi::Error::New(env, "Example exception").ThrowAsJavaScriptException();
return;
```

After throwing a JavaScript exception, the code should generally return
immediately from the native callback, after performing any necessary cleanup.

### Propagating a Node-API JS exception

```cpp
Napi::Env env = ...
Napi::Function jsFunctionThatThrows = someValue.As<Napi::Function>();
Maybe<Napi::Value> maybeResult = jsFunctionThatThrows({ arg1, arg2 });
Napi::Value result;
if (!maybeResult.To(&result)) {
// The Maybe is empty, calling into js failed, cleaning up...
// It is recommended to return an empty Maybe if the procedure failed.
return result;
}
```

If `maybeResult.To(&result)` returns false a JavaScript exception is pending.
To let the exception propagate, the code should generally return immediately
from the native callback, after performing any necessary cleanup.

### Handling a Node-API JS exception

```cpp
Napi::Env env = ...
Napi::Function jsFunctionThatThrows = someValue.As<Napi::Function>();
Maybe<Napi::Value> maybeResult = jsFunctionThatThrows({ arg1, arg2 });
if (maybeResult.IsNothing()) {
Napi::Error e = env.GetAndClearPendingException();
cerr << "Caught JavaScript exception: " + e.Message();
}
```

Since the exception was cleared here, it will not be propagated as a JavaScript
exception after the native callback returns.

<a name="noexceptions"></a>

## Handling Errors Without C++ Exceptions
Expand Down Expand Up @@ -127,7 +191,7 @@ immediately from the native callback, after performing any necessary cleanup.

```cpp
Napi::Env env = ...
Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
Napi::Function jsFunctionThatThrows = someValue.As<Napi::Function>();
Napi::Value result = jsFunctionThatThrows({ arg1, arg2 });
if (env.IsExceptionPending()) {
Error e = env.GetAndClearPendingException();
Expand All @@ -143,7 +207,7 @@ the native callback, after performing any necessary cleanup.

```cpp
Napi::Env env = ...
Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
Napi::Function jsFunctionThatThrows = someValue.As<Napi::Function>();
Napi::Value result = jsFunctionThatThrows({ arg1, arg2 });
if (env.IsExceptionPending()) {
Napi::Error e = env.GetAndClearPendingException();
Expand Down
74 changes: 74 additions & 0 deletions doc/maybe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Maybe (template)

Class `Napi::Maybe<T>` represents an maybe empty value: every `Maybe` is either
Comment thread
legendecas marked this conversation as resolved.
Outdated
`Just` and contains a value, or `Nothing`, and does not. `Maybe` types are very
common in node-addon-api code, as they represent the function may throw a
Comment thread
legendecas marked this conversation as resolved.
Outdated
JavaScript exception and cause the program unable to evaluation any JavaScript
Comment thread
legendecas marked this conversation as resolved.
Outdated
code until the exception is been handled.
Comment thread
legendecas marked this conversation as resolved.
Outdated

Typically, the value wrapped in `Napi::Maybe<T>` is [`Napi::Value`] and its
subclasses.

## Methods

### IsNothing

```cpp
template <typename T>
bool Napi::Maybe::IsNothing() const;
```

Returns if the `Maybe` is `Nothing` and does not contain a value.
Comment thread
legendecas marked this conversation as resolved.
Outdated

### IsJust

```cpp
template <typename T>
bool Napi::Maybe::IsJust() const;
```

Returns if the `Maybe` is `Just` and contains a value.

### Check

```cpp
template <typename T>
void Napi::Maybe::Check() const;
```

Short-hand for `Maybe::Unwrap()`, which doesn't return a value. Could be used
where the actual value of the Maybe is not needed like `Object::Set`.
If this Maybe is nothing (empty), node-addon-api will crash the
process.

### Unwrap

```cpp
template <typename T>
T Napi::Maybe::Unwrap() const;
Comment thread
legendecas marked this conversation as resolved.
```

Return the value of type `T` contained in the Maybe. If this Maybe is
nothing (empty), node-addon-api will crash the process.

### UnwrapOr

```cpp
template <typename T>
T Napi::Maybe::UnwrapOr(const T& default_value) const;
```

Return the value of type T contained in the Maybe, or using a default
Comment thread
legendecas marked this conversation as resolved.
Outdated
value if this Maybe is nothing (empty).

### UnwrapTo

```cpp
template <typename T>
bool Napi::Maybe::UnwrapTo() const;
Comment thread
legendecas marked this conversation as resolved.
Outdated
```

Converts this Maybe to a value of type `T` in the `out`. If this Maybe is
nothing (empty), `false` is returned and `out is left untouched.
Comment thread
legendecas marked this conversation as resolved.
Outdated

[`Napi::Value`]: ./value.md
9 changes: 9 additions & 0 deletions doc/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ To use **Node-API** in a native module:
```gyp
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
```

If you decide to use node-addon-api without C++ exceptions enabled, please
consider enabling node-addon-api safe API type guards to ensure proper
Comment thread
legendecas marked this conversation as resolved.
Outdated
exception handling pattern:

```gyp
'defines': [ 'NODE_ADDON_API_ENABLE_MAYBE' ],
```

4. If you would like your native addon to support OSX, please also add the
following settings in the `binding.gyp` file:

Expand Down
Loading