brie

This is brie Build Status

This Business Rules Integration Engine (B.R.E, or “brie”) is a transient Feature Flipping Criteria System for Node.

npm install brie

Getting Started

Below is a simple example that uses brie to deliver feature flags based on a determined (set) of User Variant(s):

// Include brie
const brie = require('brie');

// given an inbound data object called "user" plus a set of features (see below) called "featureSet"
brie.setup(
  {
    data: user,
    features: featureSet
  }
);
const flags = brie.getAll();
// expect {feature1: true, feature2: false, ... } from get() or getAll()

Criteria

Criteria are the predefined rule types that brie tests data against, per feature. Each feature in the feature set consists of at least one criteria. A feature may contain multiple criteria, joined across a logical “and” or “any” as dictated by the criteriaLogic:

  const featureSet = {
    multiPartTestCase : {
      criteria : [
        {
          has: {
            "trait": "messageCount",
            "comparison": "above",
            "value": 2
          }
        },
        {
          has: {
            "trait": "creationDate",
            "comparison": "older",
            "value": "12/Dec/2000"
          }
        }
      ],
      criteriaLogic: "any"
    }
  };
// expect {multiPartTestCase: true} from get() and getAll()

brie has:

allowIDs (object, array)

  opts = {
    "values": [...]
  }

Provided an object containing an “id” property, brie evaluates the presence of the id in the given array, checking for 1 or more entries.

allowValues (object, array)

  opts = {
    "values": [...],
    "trait": [String]
  }

Provided an object containing a noted trait, brie evaluates the presence of the trait in the given array, checking for 1 or more entries.

always (object, bool)

Always asks brie to “always” respond with the given input. Why? Code consistency, mainly.

percentScale(object, opts)

  opts = {
    percentMin:[0-1],
    percentMax:[0-1],
    salt:[number]
  }

The object.id is used to calculate a percentage, modified by the salt value. If the resulting, salted, number is within range, returns true; otherwise false.

has(test data [object], comparison data [object])

The most complex criteria mechanism, has will evaluate the test data (first argument) against the trait, comparator and value provided in the second argument. If the test data has the trait and the associated value evaluates properly considering the comparison value, then true is returned.

If the comparison object contains only trait then brie will evaluate the presence of the property on the data object. Comparison and value must be provided together, when one of them is provided.

Note: for the purpose of comparisons, “object” refers to both object and array, with the distinction being left up to the return value of the _.isArray() method or the native Array.isArray() method when availabe.

Possible comparisons are:

equals
above
below
like
longer
shorter

is (object (source), object (options))

Tests if a key from a source object has property of a noted type.

Options

rejectValues (object, array)

  opts = {
    "values": [...],
    "trait": [String]
  }

Provided an object containing a noted trait, brie evaluates the presence of the trait in the given array, checking for 1 or more entries.

Features

Features contain sets of criteria to test users against. The value associated with the criteria is passed in as the data argument of the criteria function. A user will have a featured enabled if they match all listed criteria, otherwise the feature is disabled. Features can include other optional properties for context. Features are described as follows:

const ExampleFeaturesObject = {
  "canCheckAlways": {
    "criteria": [
      {
        "always": false
      }
    ]
  },
  "canCheckHasString": {
    "criteria": [
      {
        "has": {
          "trait": "hasStringValue",
          "comparison": "equals",
          "value": "a string check value"
        }
      }
    ]
  },
  "canCheckType": {
    "criteria": [
      {
        "is": {
          "trait": "myData.nested.key",
          "type": "number"
        }
      }
    ]
  },
  "canCheckHigherNumber": {
    "criteria": [
      {
        "has": {
          "trait": "hasNumberValue",
          "comparison": "above",
          "value": 1
        }
      }
    ]
  },
  "canCheckLowerDate": {
    "criteria": [
      {
        "has": {
          "trait": "hasDateValue",
          "comparison": "younger",
          "value": new Date(2000, 1, 1, 1, 22, 0)
        }
      }
    ]
  },
  "canCheckRejectValues": {
    "criteria": [
      {
        "rejectValues": {
          "values": [1234, 5678, 91011, 123456789],
          "trait": "propertyName"
        }
      }
    ]
  },
  "canCheckAllowValues": {
    "criteria": [
      {
        "allowValues": {
          "values": [1234, 5678, 91011, 123456789],
          "trait": "id"
        }
      }
    ]
  }
}

Usage

Object setup(options)         // brie needs to be initialized with a data object and a set of features.  Don't try to make brie do stuff without setting up first. That makes brie angry.
Bool   get(string feature)    // asks brie if the feature is enabled.
Object getAll()               // requests the full evaluation of features from brie

Setup

In the setup (initializer), brie accepts:

Returns brie.

Once initialized, via setup(), brie can be queried for the outcome of any or all features.

get

get returns the outcome of a single feature, and requires the string name of the feature, as an argument, and is invoked as

const isHigherNumber = brie.get('canCheckHigherNumber');
// isHigherNumber = true;

getAll

getAll returns a hash of all features and their evaluated value, including overrides, as a shallow javascript object.

const allFeatures = brie.getAll();
// allFeatures = {
// canCheckAlways: true,
// canCheckHasString: true,
// canCheckHigherNumber: false,
// canCheckLowerDate: false,
// canCheckRejectValues: true,
// canCheckAllowValues: true
// }

Chaining

A single method can be chained against the setup method. setup returns brie, which has both a get and getAll method. Further chaining is not available, since get returns a boolean and getAll returns an object.

const allFeatures = brie.setup({
    data: data_in,
    features: flags_in,
    overrides: overrides,
    showLogs: true
}).getAll()