fflip
Follow @FredKSchott for development news and updates!
Working on an experimental new design? Starting a closed beta? Rolling out a new feature over the next few weeks? Fa-fa-fa-flip it! fflip gives you complete control over releasing new functionality to your users based on thier user id, join date, membership status, and whatever else you can think of. fflip's goal is to be the most extendable and customizable feature flipping/toggling module out there.
- Describes custom criteria and features using easy-to-read JSON
- Delivers features down to the client for additional client-side feature flipping
- Includes Express Middleware for easy integration with Express applications
- Everything-Agnostic: Supports any database, user representation or framework you can throw at it
npm install fflip --save
##Getting Started
Below is a simple example that uses fflip to deliver a closed beta to a fraction of users:
var fflip = require('fflip');
fflip.config({
criteria: ExampleCriteriaObject,
features: ExampleFeaturesObject
});
var Features = fflip.featuresForUser(someFreeUser);
if(Features.closedBeta) {
console.log('Welcome to the Closed Beta!');
}
###Criteria
Criteria are the rules that features can test users against. Each rule takes a user and a data argument to test against, and returns true/false if the user matches that criteria. The data argument can be any type, as long as you handle it correctly in the function you describe.
var ExampleCriteriaObject = {
isPaidUser: function(user, isPaid) {
return user.isPaid == isPaid;
},
percentageOfUsers: function(user, percent) {
return (user.id % 100 < percent * 100);
},
allowUserIDs: function(user, idArr) {
for(var id in idArr) {
if(user.id == idArr[id]) return true;
}
return false;
}
}
###Features
Features are 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 are described as follows:
var ExampleFeaturesObject = {
paidFeature: {
isPaidUser: true
},
closedBeta: {
allowUserIDs: [20,30,80,181],
},
newFeatureRollout: {
isPaidUser: false,
percentageOfUsers: 0.50,
}
}
##Usage
void config(options) // Configure fflip (see below)
Object featuresForUser(user) // Return object of true/false for all features for user
Bool userHasFeature(user, featureName) // Return true/false if featureName is enabled for user
void reload() // Force a reload of criteria/features
void __express(app) // Connect with an Express app (see below)
Configure fflip using any of the following options:
fflip.config({
criteria: {},
features: {},
reload: 30,
});
###Loading Features & Criteria Dynamically
fflip also accepts functions for loading criteria and features. If fflip is passed a funciton with no arguments it will call the function and accept the return value. To load asyncronously, pass a function that sends a features/criteria data object to a callback. fflip will recieve the callback and set the data accordingly. In both cases, fflip will save these functions and call them again every X seconds, as set by the reload parameter.
var getCriteriaSync = function() {
var collection = db.collection('criteria');
var criteriaArr = collection.find().toArray();
return criteriaObj;
}
var getFeaturesAsync = function(fflip_callback) {
var collection = db.collection('features');
collection.find().toArray(function(err, featuresArr) {
fflip_callback(featuresObj);
});
}
fflip.config({
criteria: getCriteriaSync,
features: getFeaturesAsync,
reload: 60
});
##Express Integration
fflip provides easy integration with the popular web framework Express. Just call fflip.__express(app)
wherever you set up your server to enable the following:
####A route for manually flipping on/off features
If you have cookies enabled, you can visit /fflip/:name/:action
to manually override a feature to always return true/false for your own session. Just replace ':name' with the Feature name and ':action' with 1 to enable, 0 to disable, or -1 to reset (remove the cookie override). This override is stored in the user's cookie.
####req.fflip
A fflip object is attached to the request, and includes the following funciontality:
req.fflip = {
flags: Any override flags set by the fflip cookie
features: A user's fflip features object. Undefined until setFeatures() is called.
setFeatures(user): Given a user, attaches the features object to the request (at req.fflip.features)
hasFeature(featureName): Given a feature name, returns the feature boolean, or null if setFeatures() has't been called
}
To avoid polluting the request object, All fflip functionality is contained within req.fflip. But (If your implementation allows it) you can add aliases directly onto the request object.
####Automatically deliver Features to the client
The fflip Express middleware wraps res.render() to always the req.fflip.features object as a Features
template variable. To deliver this down to the client, just make sure your template contains the code <script>var Features = <%= Features %></script>
.
##Special Thanks
Original logo designed by Luboš Volkov