question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: Support for query params

See original GitHub issue

It would be useful in my app to have feature flags which are switched off but can be switched on via a query param. This would allow specific users to test a feature before it is enabled for all users.

For example www.app.com?enabledFeatures=new-billing,new-settings would turn on the new-billing and new-settings flags.

More details:

  • The query param would default to enabledFeatures= but can be configured. (I don’t think this could be called features= because this would have to be a property on the controller and it might conflict with the service).
  • This whole query-param option could be switched on or off.

In the future we could also consider:

  • Support specifying for each feature flag if it can be toggled via a queryParam
  • Support disabling features via query param, although I don’t see this as being as useful…

Please let me know if you think this is a good idea. I’d be happy to submit a PR.

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:5
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
kategenglercommented, Jul 7, 2022

Thanks for sharing your solution.

I wouldn’t recommend using Ember.Evented nor initializers in new code, so I would stick with the first way, for now.

1reaction
rtabladacommented, Jul 7, 2022

We just implemented an augmentation/extension for the features service to support query params and sessionStorage persistence (for tab persistence for FFs), I think a different way would be to have better docs and hooks for enable/disabling features.

This way teams can have a dedicated way to initialize and persist FFs with QPs, dynamic HTML Head, server request, etc.

This is our extended features service:

import Features from 'ember-feature-flags/services/features';
import config from '../config/environment';
import { inject as service } from '@ember/service';

const FEATURE_QP_REGEX = /^feature\[(.*)\]/;

export default class FeaturesService extends Features {
  config = config;
  @service('router') router;

  init() {
    super.init(...arguments);

    if (config.featureFlags) {
      let featureFlags = {
        ...config.featureFlags,
        ...this.sessionFeatureFlags,
        ...this.initQueryFeatureFlags(),
      };

      this.setup(featureFlags);
    }
  }

  get sessionFeatureFlags() {
    return JSON.parse(sessionStorage.featureFlags ?? '{}');
  }

  set sessionFeatureFlags(value = {}) {
    sessionStorage.featureFlags = JSON.stringify(value);
  }

  initQueryFeatureFlags() {
    let featureFlags = {};
    const params = new URLSearchParams(window.location.search);

    // Search query params for feature flags
    params.forEach((value, key) => {
      const matches = key.match(FEATURE_QP_REGEX);
      if (matches) {
        let [, flag] = matches;

        featureFlags[flag] = value !== 'false' ? true : false;
      }
    });

    return featureFlags;
  }

  persistFeatureFlag(flag, value) {
    let sessionFeatureFlags = this.sessionFeatureFlags;

    if (config.featureFlags[flag] == value) {
      delete sessionFeatureFlags[flag];
    } else {
      sessionFeatureFlags[flag] = value;
    }

    this.sessionFeatureFlags = sessionFeatureFlags;
  }

  enable(flag) {
    super.enable(flag);

    this.persistFeatureFlag(flag, true);
  }

  disable(flag) {
    super.disable(flag);

    this.persistFeatureFlag(flag, false);
  }
}

But, I think that there could be an API using initializers to have an app initializer like and the above implementation would become:

import { featureFlagInitializer } from 'ember-feature-flags';
import config from '../../config/environment';

const getSessionFeatureFlags = () =>  JSON.parse(sessionStorage.featureFlags ?? '{}');

const getQueryFeatureFlags = (featureFlags) => {
  let featureFlags = {};
  const params = new URLSearchParams(window.location.search);

  // Search query params for feature flags
  params.forEach((value, key) => {
    const matches = key.match(FEATURE_QP_REGEX);
    if (matches) {
      let [, flag] = matches;

      featureFlags[flag] = value !== 'false' ? true : false;
    }
  });

  return featureFlags;
}

export const initialize = featureFlagInitializer((featuresService, appInstanace) => {
  // New function that is called and passed to `setup`
  featuresService.addFeatureFlagInitializer((featureFlags) => {
    return {
      ...featureFlags,
      ...getSessionFeatureFlags(),
      ...getQueryFeatureFlags(featureFlags),
    }
  });

  featuresService.on('toggleFeature', (flag, value) => {
    let sessionFeatureFlags = getSessionFeatureFlags();

    if (config.featureFlags[flag] == value) {
      delete sessionFeatureFlags[flag];
    } else {
      sessionFeatureFlags[flag] = value;
    }

    sessionStorage.featureFlags = JSON.stringify(sessionFeatureFlags);
  });
});

export default {
    name: 'feature-flags',
    initialize
};

The change would be adding some initialization hook and then using Ember.Evented to an event listener for toggleFeature (I’m using a single event rather than having separate enable/disable but 🤷🏽)

Read more comments on GitHub >

github_iconTop Results From Across the Web

RFC 3986 Support for Encoding Query Parameters
The REST Adapter supports encoding query parameters in accordance with RFC 3986 standards. The default behavior is to encode the query parameters following ......
Read more >
RFC 1808 Relative Uniform Resource Locators - IETF
It is a companion to RFC 1738, "Uniform Resource Locators (URL)" [2], which specifies the syntax and semantics of absolute URLs. A common...
Read more >
rfc6920.txt - » RFC Editor
Query Parameters : A "tag=value" list of optional query parameters as are used with HTTP URLs [RFC2616] with a separator character '&' between...
Read more >
Query string - Wikipedia
A query string is a part of a uniform resource locator (URL) that assigns values to specified parameters. A query string commonly includes...
Read more >
Is a url query parameter valid if it has no value? - Stack Overflow
The URI RFC doesn't mandate a format for the query string. Although it is recognized that the query string will often carry name-value...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found