/dual-api

Make your module implement dual APIs, callback API and thenable (Promise) API.

Primary LanguageJavaScriptMIT LicenseMIT

dualAPI

npm GitHub issues dependencies license

Make your module implement dual APIs.
When the method of your module is called, if a callback Function is appended to the arguments, the method works as callback API. Otherwise the method returns a thenable Promise instance.

For example:
This egg module exports two methods.
The egg.fry method returns 'fried egg' if it is called with 'oil', otherwise it returns [Error: burnt egg]. The egg.boil method returns 'boiled egg' if it is called with 'water', otherwise it returns [Error: broken egg]. These are the same as a function that is passed to Promise constructor.
After setting up exports, call require('dual-api').

// `egg` module

function fry(resolve, reject, doWith) {
  console.log(`An egg is fried with ${doWith || 'nothing'}.`);
  setTimeout(() => {
    if (doWith === 'oil') {
      resolve('fried egg');
    } else {
      reject(new Error('burnt egg'));
    }
  }, 3000);
}

function boil(resolve, reject, doWith) {
  console.log(`An egg is boiled with ${doWith || 'nothing'}.`);
  setTimeout(() => {
    if (doWith === 'water') {
      resolve('boiled egg');
    } else {
      reject(new Error('broken egg'));
    }
  }, 3000);
}

exports.fry = fry;
exports.boil = boil;

require('dual-api');

A code that uses egg module:

const egg = require('egg');

// Call methods as callback API:

egg.fry('oil', function(error, returned) {
  if (error) {
    console.error(error);
  } else {
    console.log(`Got a ${returned}.`);
  }
});

egg.boil('water', function(error, returned) {
  if (error) {
    console.error(error);
  } else {
    console.log(`Got a ${returned}.`);
  }
});

// Call methods as thenable API:

egg.fry('oil')
  .then(returned => { console.log(`Got a ${returned}.`); })
  .catch(error => { console.error(error); });

egg.boil('water')
  .then(returned => { console.log(`Got a ${returned}.`); })
  .catch(error => { console.error(error); });

Results:

An egg is fried with oil.
Got a fried egg.
An egg is boiled with water.
Got a boiled egg.
An egg is fried with oil.
Got a fried egg.
An egg is boiled with water.
Got a boiled egg.

A single method that is set to module.exports is also supported.
For example, egg-fly module that exports only fry method:

// `egg-fly` module

// There is `fry` function.

module.exports = fry;
require('dual-api');

A code that uses egg-fly module:

const eggFly = require('egg-fly');

// Call method as callback API:

eggFly('oil', function(error, returned) {
  if (error) {
    console.error(error);
  } else {
    console.log(`Got a ${returned}.`);
  }
});

// Call method as thenable API:

eggFly('oil')
  .then(returned => { console.log(`Got a ${returned}.`); })
  .catch(error => { console.error(error); });

By default, all exported methods implement dual APIs.
You can specify methods that implement dual APIs by using exports._dualApi_methodNames array.
For example, the module exports fry, boil and beatUp methods, and only boil and beatUp methods implement dual APIs.

// `egg` module

// There are `fry`, `boil` and `beatUp` functions.

exports.fry = fry;
exports.boil = boil;
exports.beatUp = beatUp;

exports._dualApi_methodNames = ['boil', `beatUp`];

require('dual-api');