Skip to content

Design Decisions: NodeJS Binding API

RamyElkest edited this page May 29, 2018 · 1 revision

As of 2018 there are there are at least three main APIs to create node.js bindings.

Node Native

node.h

Provides an interface to the V8 node engine directly.

Pros
  • Low level constructs will allow us to achieve any flows we may need
Cons
  • V8 Specific

Native Abstractions for Node

nan.h

Provides a thin wrapper on top of node native to protect the client from breaking changes in V8 (node native)

Pros
  • Shields our client from V8 changes
  • Easier interface / development
  • Existing examples eg. node-libvirt
Cons
  • The wrapper limits our access to some core constructs (eg. no direct access to libuv, async via Workers) which may be needed
  • V8 Specific

N-API

node_api.h

The ABI Stable Node API project (N-API) is a new experimental stable binary compatible node C API that abstracts the underlying node VM (eg. V8 or ChakraCore).

The goal of this project is to provide a stable Node API for native module developers. N-API aims to provide ABI compatibility guarantees across different Node versions and also across different Node VMs - allowing N-API enabled native modules to just work across different versions and flavors of Node.js without recompilations.

Pros
  • API/ABI node compatibility
  • Advocated/invested in by Node
  • Direct access to core constructs (eg. libuv)
Cons
  • As a new interface (although stable now) we might face some unmet issues.
  • Minimal real world examples

Node-Addon-API

napi.h

Node-Addon-API is a thin C++ wrapper on top of node_api.h that makes the interface easier to work with (similar to NaN).

Pros
  • Easier interface / development
Cons
  • The wrapper limits our access to some core constructs (eg. no direct access to libuv, async via Workers) which may be needed

Chosen Direction

Following from the above, to be future proof NAPI(/Node-Addon-API) seems to be the way to go. The only questions are whether it's mature enough to:

Support our needs

For now, in addition to sync calls, we foresee the needs to asynchronous multithreaded calls, and event management. N-API provides an API to manage asynchronous calls and provides direct access to libuv object for events management.

Survive as the recommended API

Given N-API's roadmap progress and exiting experimental status, the core development was successful and the focus is now shifting on community adoption with a few projects migrated.

C API vs C++ API

The N-API is a C API that ensures ABI stability across Node.js versions and different compiler levels. However, we also understand that a C++ API can be easier to use in many cases. To support these cases we expect there to be one or more C++ wrapper modules that provide an inlineable C++ API. Binaries built with these wrapper modules will depend on the symbols for the N-API C based functions exported by Node.js. These wrappers are not part of N-API, nor will they be maintained as part of Node.js. One such example is: node-addon-api.

Node-Addon-API (C++ API) suffers mostly the same limitations as NaN with the V8 as low level constructs are abstracted in the API. Perhaps the API is sufficient for our needs, however it's better to be safe than sorry as this stage. Additionally it is mentioned that node-addon-api will not be maintained by nodejs (this may no longer be true) thus might lead to issues in the future.

Conclusion

N-API is the NodeJS recommended API to allow binary compatibility across node versions and vms. We've picked the C API node_api.h as it provides low level constructs that may be needed in our flow, and keeps us close to the source (for potential fixes etc).