ffclient

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 17, 2020 License: MIT Imports: 11 Imported by: 25

README ΒΆ

πŸŽ›οΈ go-feature-flag Tweet

Build Status Coverage Status Sonarcloud Status GitHub FOSSA Status
Release version GoDoc Go version

A feature flag solution, with YAML file in the backend (S3, HTTP, local file ...).
No server to install, just add a file in a central system (HTTP, S3, ...) and all your services will react to the changes of this file.

If you are not familiar with feature flags also called feature Toggles you can read this article of Martin Fowler that explain why this is a great pattern.
I've also write an article that explain why feature flags can help you to iterate quickly.

Installation

go get github.com/thomaspoignant/go-feature-flag

Quickstart

First, you need to initialize the ffclient with the location of your backend file.

err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    HTTPRetriever: &ffClient.HTTPRetriever{
        URL:    "http://example.com/test.yaml",
    },
})
defer ffclient.Close()

This example will load a file from an HTTP endpoint and will refresh the flags every 3 seconds.

Now you can evalute your flags anywhere in your code.

user := ffuser.NewUser("user-unique-key")
hasFlag, _ := ffclient.BoolVariation("test-flag", user, false)
if hasFlag {
    // flag "test-flag" is true for the user
} else {
    // flag "test-flag" is false for the user
}

Where do I store my flags file

go-feature-flags support different ways of retrieving the flag file.
We can have only one source for the file, if you set multiple sources in your configuration, only one will be take in consideration.

From a file
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    LocalFile: "file-example.yaml",
})
defer ffclient.Close()

I will not recommend using a file to store your flags except if it is in a shared folder for all your services.

From an HTTP endpoint
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
     HTTPRetriever: &ffClient.HTTPRetriever{
        URL:    "http://example.com/test.yaml",
    },
})
defer ffclient.Close()

To configure your HTTP endpoint:

  • URL: location of your file. MANDATORY
  • Method: the HTTP method you want to use (default is GET).
  • Body: If you need a body to get the flags.
  • Header: Header you should pass while calling the endpoint (useful for authorization).
From a S3 Bucket
err := ffclient.Init(ffclient.Config{
    PollInterval: 3,
    S3Retriever: &ffClient.S3Retriever{
        Bucket: "tpoi-test",
        Item:   "test.yaml",
        AwsConfig: aws.Config{
            Region: aws.String("eu-west-1"),
        },
    },
})
defer ffclient.Close()

To configure your S3 file location:

  • Bucket: The name of your bucket. MANDATORY
  • Item: The location of your file in the bucket. MANDATORY
  • AwsConfig: An instance of aws.Config that configure your access to AWS (see this documentation for more info). MANDATORY

Flags file format

go-feature-flag is to avoid to have to host a backend to manage your feature flags and to keep them centralized by using a file a source.
Your file should be a YAML file with a list of flags (see example).

A flag configuration looks like:

test-flag:
  percentage: 100
  rule: key eq "random-key"
  true: true
  false: false
  default: false
  disable: false
test-flag mandatory Name of the flag. It should be unique.
percentage optional Percentage of the users affect by the flag.
Default value is 0
rule optional This is the query use to select on which user the flag should apply.
Rule format is describe in the rule format section.
If no rule set, the flag apply to all users (percentage still apply).
true mandatory The value return by the flag if apply to the user (rule is evaluated to true) and user is in the active percentage.
false mandatory The value return by the flag if apply to the user (rule is evaluated to true) and user is not in the active percentage.
default mandatory The value return by the flag if not apply to the user (rule is evaluated to false).
disable optional True if the flag is disabled.

Rule format

The rule format is based on the nikunjy/rules library.

All the operations can be written capitalized or lowercase (ex: eq or EQ can be used).
Logical Operations supported are AND OR.

Compare Expression and their definitions (a|b means you can use either one of the two a or b):

eq|==: equals to 
ne|!=: not equals to
lt|<: less than 
gt|>: greater than
le|<=: less than equal to
ge|>=: greater than equal to 
co: contains 
sw: starts with 
ew: ends with
in: in a list
pr: present
not: not of a logical expression
Examples
  • Select a specific user: key eq "example@example.com"
  • Select all identified users: anonymous ne true
  • Select a user with a custom property: userId eq "12345"

How can I contribute?

This project is open for contribution, see the contributor's guide for some helpful tips.

Documentation ΒΆ

Overview ΒΆ

Package ffclient aids adding instrumentation to have feature flags in your app without any backend server.

Summary ΒΆ

This package and its subpackages contain bits of code to have an easy feature flag solution with no complex installation to do on your infrastructure and without using 3rd party vendor for this.

The ffclient package provides the entry point - initialization and the basic method to get your flags value.

Before using the module you need to initialized it this way:

func main() {
  err := ffclient.Init(ffclient.Config{
           PollInterval: 3,
           HTTPRetriever: &ffClient.HTTPRetriever{
             URL:    "http://example.com/test.yaml",
           },
         })
  defer ffclient.Close()
  ...

This example will load a file from an HTTP endpoint and will refresh the flags every 3 seconds.

Now you can evalute your flags anywhere in your code.

func main() {
  ...
  user := ffuser.NewUser("user-unique-key")
  hasFlag, _ := ffclient.BoolVariation("test-flag", user, false)
  if hasFlag {
    //flag "test-flag" is true for the user
  } else {
    // flag "test-flag" is false for the user
  }
  ...

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

This section is empty.

Functions ΒΆ

func BoolVariation ΒΆ

func BoolVariation(flagKey string, user ffuser.User, defaultValue bool) (bool, error)

BoolVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func Close ΒΆ

func Close()

Close the component by stopping the background refresh and clean the cache.

func Float64Variation ΒΆ

func Float64Variation(flagKey string, user ffuser.User, defaultValue float64) (float64, error)

Float64Variation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func Init ΒΆ

func Init(config Config) error

Init the feature flag component with the configuration of ffclient.Config

func main() {
  err := ffclient.Init(ffclient.Config{
           PollInterval: 3,
           HTTPRetriever: &ffClient.HTTPRetriever{
             URL:    "http://example.com/test.yaml",
           },
         })
  defer ffclient.Close()

func IntVariation ΒΆ

func IntVariation(flagKey string, user ffuser.User, defaultValue int) (int, error)

IntVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func JSONArrayVariation ΒΆ

func JSONArrayVariation(flagKey string, user ffuser.User, defaultValue []interface{}) ([]interface{}, error)

JSONArrayVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func JSONVariation ΒΆ

func JSONVariation(
	flagKey string, user ffuser.User, defaultValue map[string]interface{}) (map[string]interface{}, error)

JSONVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

func StringVariation ΒΆ

func StringVariation(flagKey string, user ffuser.User, defaultValue string) (string, error)

StringVariation return the value of the flag in boolean. An error is return if you don't have init the library before calling the function. If the key does not exist we return the default value.

Types ΒΆ

type Config ΒΆ

type Config struct {
	PollInterval  int // Poll every X seconds
	LocalFile     string
	HTTPRetriever *HTTPRetriever
	S3Retriever   *S3Retriever
}

Config is the configuration of go-feature-flag. PollInterval is the interval in seconds where we gonna read the file to update the cache. You should also have a retriever to specify where to read the flags file.

func (*Config) GetRetriever ΒΆ

func (c *Config) GetRetriever() (retriever.FlagRetriever, error)

GetRetriever is used to get the retriever we will use to load the flags file.

type HTTPRetriever ΒΆ

type HTTPRetriever struct {
	URL    string
	Method string
	Body   string
	Header http.Header
}

HTTPRetriever is a configuration struct for an HTTP endpoint retriever.

type S3Retriever ΒΆ

type S3Retriever struct {
	Bucket    string
	Item      string
	AwsConfig aws.Config
}

S3Retriever is a configuration struct for a S3 retriever.

Directories ΒΆ

Path Synopsis
Package ffuser defines the go-feature-flag model for user properties.
Package ffuser defines the go-feature-flag model for user properties.
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL