🏗️ Generate OpenFeature flag manifest
This feature is experimental and may change in the future.
The OpenFeature cli allow code generation for flag accessors for OpenFeature.
This allows to have a type safe way to access your flags in your code based on a flag manifest you can provide to the OpenFeature cli.
To generate the OpenFeature flag manifest you can use the generate manifest
command of the go-feature-flag-cli
,
it will generate a flag manifest file compatible with the OpenFeature cli
that you can use.
Add information to your flags
To generate the flag manifest you need to provide information about your flags in your configuration file.
To do this we leverage the metadata
field of your flags in your configuration file, to provide information about the flag.
You need to provide 2 fields in the metadata
to allow the flag to be generated in the flag manifest:
defaultValue
: (mandatory) The default value of the flag.description
: A description of the flag.
If you don't provide a defaultValue
field in your metadata the flag will be ignored in the flag manifest.
enableFeatureA:
variations:
var_a: false
var_b: true
defaultRule:
variation: var_a
metadata:
description: Controls whether Feature A is enabled.
defaultValue: false
usernameMaxLength:
variations:
var_a: 20
var_b: 30
defaultRule:
variation: var_a
metadata:
description: Maximum allowed length for usernames.
defaultValue: 50
# ...
Install the Command Line
Check the installation guide to install the go-feature-flag-cli
.
Generate the flag manifest
go-feature-flag-cli generate manifest \
--config="<location_of_your_flag_configuration_file>" \
--flag_manifest_destination="<destination_of_your_flag_manifest>"
param | description |
---|---|
--flag_manifest_destination | (mandatory) The destination where your manifest will be stored. |
--config | The location of your configuration file. (if not provided we will search a file named flags.goff.yaml in one of this directories ./ , /goff/ , /etc/opt/goff/ . |
--format | The format of your configuration flag (acceptable values:yaml , json , toml ).Default: yaml |
Example of flag manifest
{
"flags": {
"enableFeatureA": {
"flagType": "boolean",
"defaultValue": false,
"description": "Controls whether Feature A is enabled."
},
"usernameMaxLength": {
"flagType": "integer",
"defaultValue": 50,
"description": "Maximum allowed length for usernames."
},
"greetingMessage": {
"flagType": "string",
"defaultValue": "Hello there!",
"description": "The message to use for greeting users."
}
}
}
Use the OpenFeature cli to generate the flag accessors
To install the OpenFeature cli you can follow the installation guide from the repository.
Once you have the OpenFeature cli installed you can use the generate
command to generate the flag accessors.
openfeature-cli generate go \
--flag_manifest_path="<destination_of_your_flag_manifest>" \
--package_name="<name of your GO package>" \
--output_path="<destination_go_file>"
Here the example is using code generation in GO, but react and other languages are supported.
Refer to the OpenFeature cli documentation for more information.
As the result of this command, you will have a file with the flag accessors generated based on the flag manifest you provided. You will be able to use a type-safe way to access your flags in your code.
Output file example
// AUTOMATICALLY GENERATED BY OPENFEATURE CODEGEN, DO NOT EDIT.
package feature_flags
import (
"context"
"github.com/open-feature/go-sdk/openfeature"
)
type BooleanProvider func(ctx context.Context, evalCtx openfeature.EvaluationContext) (bool, error)
type BooleanProviderDetails func(ctx context.Context, evalCtx openfeature.EvaluationContext) (openfeature.BooleanEvaluationDetails, error)
type FloatProvider func(ctx context.Context, evalCtx openfeature.EvaluationContext) (float64, error)
type FloatProviderDetails func(ctx context.Context, evalCtx openfeature.EvaluationContext) (openfeature.FloatEvaluationDetails, error)
type IntProvider func(ctx context.Context, evalCtx openfeature.EvaluationContext) (int64, error)
type IntProviderDetails func(ctx context.Context, evalCtx openfeature.EvaluationContext) (openfeature.IntEvaluationDetails, error)
type StringProvider func(ctx context.Context, evalCtx openfeature.EvaluationContext) (string, error)
type StringProviderDetails func(ctx context.Context, evalCtx openfeature.EvaluationContext) (openfeature.StringEvaluationDetails, error)
var client openfeature.IClient = nil
// Controls whether Feature A is enabled.
var EnableFeatureA = struct {
// Value returns the value of the flag EnableFeatureA,
// as well as the evaluation error, if present.
Value BooleanProvider
// ValueWithDetails returns the value of the flag EnableFeatureA,
// the evaluation error, if any, and the evaluation details.
ValueWithDetails BooleanProviderDetails
}{
Value: func(ctx context.Context, evalCtx openfeature.EvaluationContext) (bool, error) {
return client.BooleanValue(ctx, "enableFeatureA", false, evalCtx)
},
ValueWithDetails: func(ctx context.Context, evalCtx openfeature.EvaluationContext) (openfeature.BooleanEvaluationDetails, error){
return client.BooleanValueDetails(ctx, "enableFeatureA", false, evalCtx)
},
}
// Maximum allowed length for usernames.
var UsernameMaxLength = struct {
// Value returns the value of the flag UsernameMaxLength,
// as well as the evaluation error, if present.
Value IntProvider
// ValueWithDetails returns the value of the flag UsernameMaxLength,
// the evaluation error, if any, and the evaluation details.
ValueWithDetails IntProviderDetails
}{
Value: func(ctx context.Context, evalCtx openfeature.EvaluationContext) (int64, error) {
return client.IntValue(ctx, "usernameMaxLength", 50, evalCtx)
},
ValueWithDetails: func(ctx context.Context, evalCtx openfeature.EvaluationContext) (openfeature.IntEvaluationDetails, error){
return client.IntValueDetails(ctx, "usernameMaxLength", 50, evalCtx)
},
}
func init() {
client = openfeature.GetApiInstance().GetClient()
}