0.0.8 • Published 8 years ago

express-feature-flags v0.0.8

Weekly downloads
-
License
MIT
Repository
-
Last release
8 years ago

express-feature-flags

A tool for constructing complex feature-flags with Express

npm Version

Example

// app/features-schema.js
const administrator = {
  type: 'contains',
  key: 'user.role',
  comparison: ['admin', 'root', 'sysadmin']
}

const features = {
  'administrator': administrator,
  'regular-user': Object.assign({ inverse: true }, administrator),
  'hidden-page': [{
    type: 'eq',
    key: 'user.authenticated',
    comparison: true
  }, {
    type: 'contains',
    key: 'locales',
    comparison({ user }) { return user.locale; }
  }, {
    type: 'gt',
    key: 'timestamp',
    comparison: 1449297410423
  }]
};

export default features;
// app/server.js
import express from 'express';
import featureFlags from 'express-feature-flags';
import featureSchema from './features-schema';

const app = express();
const feature = featureFlags.create(app, featureSchema);

// optional: add a custom predicate
// supported of the box: eq, neq, contains, gt, gte, lt, lte
feature.builder.registerPredicate('blank', (value/*, rule */) => {
  if (typeof value === 'undefined' || value === '') {
    return true;
  }

  return value.length && value.length === 0;
});

app.locals.locales = ['en-US', 'en-CA'];

app.use((req, res, next) => {
  Object.assign(res.locals, {
    timestamp: new Date().getTime(),
    user: {
      authenticated: req.user.isAuthenticated,
      role: req.user.role,
      locale: req.locale.code
    }
  });

  next();
});

/**
 * Responsible for constructing the enabled feature list on per-request basis.
 * Ordering the middleware after your request context is finish being
 * built BUT BEFORE any logic that checks if a feature is enabled
 * is very important!
 */
app.use(feature.register());

// example of a utility function used to guard routes/middleware
function is(key, middlewareFunc) {
  return function(req, res, next) {
    if (res.isEnabled(key)) {
      return middlewareFunc.call(this, req, res, next);
    }

    next();
  }
}

app.use('/hidden', is('hidden-page', (req, res, next) => {
  res.render('pages/hidden-page');
}));

app.use('/admin', is('administrator', (req, res, next) => {
  res.render('pages/hidden-page');
}));

app.use('/', (req, res) => {
  if (res.isEnabled('administrator')) {
    return res.render('pages/home/power-user');
  }

  res.render('pages/home/regular-user');
});

Templating Engine Integration

Handlebars

Template Helper

Handlebars.registerHelper('is-enabled', function(key, options) {
  return options.data.isEnabled(key);
});

Exposing Feature Flags

Handlebars.registerHelper('json', function(context) {
  return JSON.stringify(context);
});
window.FEATURES = {{{json @root.enabled}}}
0.0.8

8 years ago

0.0.7

8 years ago

0.0.6

8 years ago

0.0.5

8 years ago

0.0.4

8 years ago

0.0.3

8 years ago

0.0.2

8 years ago

0.0.1

8 years ago