Search code examples
microservicesbackendweb-api-testingfeature-flags

Is passing feature flags in HTTP headers a good idea?


My backend is composed of multiple microservices that talk to each other via HTTPs. In each service, there is a simple feature flag manager that reads from a configuration file and decides whether or not a feature is enabled, similar to the following:

{
   "feature1" : true,
   "feature2" : false
}

This file is later read by the runtime, and the code path is diverged based on its values:

if (IsFeatureEnabled("feature1")
{
   DoThis();
}

if (IsFeatureEnabled("feature2")
{
   DoThat();
}

If features are exposed in an endpoint, and I want to write API tests that would cover feature1 and feature2. What is the best way to do this without having to modify the configuration between test runs?

I thought of an idea that could introduce some dynamism to my feature flags, which would be passing the desired flags values that should override the configuration ones in a request headers:

x-feature-flags: feature1:true,feature2:false

...where I specify what features I want on/off. The feature manager would still read the config normally, but any features specified in the header would be overridden. Effectively making them dynamic with each HTTP call.

What downsides does my approach introduce? Is there an alternate and better way of doing this? as this feels a bit hack-ish.

Cheers.


Solution

  • The main downside is if that behavior reached production, people could exploit that behavior to control the internals of the live system. Say this was a sales website and they turned off the "credit card verification" feature or something.

    To avoid this, I would abstract away the flag manager so that in the production environment it reads a file, but in the test environment it reads another source, which can be controlled by the test runner.

    That way the toggling behavior is not part of the program itself, but part of the environment around it.

    Without knowing more about your language, framework etc. its hard to give examples. if you are in an object oriented environment you could have a FileFlagManager and a TestHarnessFlagManager, that share an interface.