OpenFeature Gleam SDK
OpenFeature is an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool.
This repository contains the unofficial SDK implementation of the specification for the Gleam programming language.
🚀 Quick start
Requirements
- Gleam 1+
Install
gleam add openfeature
Usage
import gleam/bool
import gleam/dict
import gleam/dynamic
import gleam/io
import gleam/option.{None}
import openfeature
import openfeature/client
import openfeature/evaluation_context
import openfeature/providers/in_memory
pub fn main() {
// flags defined in memory
let v2_flag =
in_memory.Flag(
default_variant: "off",
variants: dict.from_list([
#("off", dynamic.from(False)),
#("on", dynamic.from(True)),
]),
context_evaluator: None,
)
let flags = dict.from_list([#("v2_enabled", v2_flag)])
// configure a provider
let _ = openfeature.set_provider(in_memory.provider(flags))
// get a bool flag value
let flag_value =
openfeature.get_client()
|> client.get_bool_value("v2_enabled", False, evaluation_context.empty())
// use the returned flag value
io.println("`v2_enabled` evaluated to: " <> bool.to_string(flag_value))
}
Further documentation can be found at https://hexdocs.pm/openfeature.
🌟 Features
Status | Features | Description |
---|---|---|
✅ | Providers | Integrate with a commercial, open source, or in-house feature management tool. |
✅ | Targeting | Contextually-aware flag evaluation using evaluation context. |
❌ | Hooks | Add functionality to various stages of the flag evaluation life-cycle. |
❌ | Logging | Integrate with popular logging packages. |
✅ | Domains | Logically bind clients with providers. |
❌ | Eventing | React to state changes in the provider or flag management system. |
✅ | Shutdown | Gracefully clean up a provider during application shutdown. |
⚠️ | Extending | Extend OpenFeature with custom providers and hooks. |
Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌
Providers
Providers are an abstraction between a flag management system and the OpenFeature SDK. Look here for a complete list of available providers. If the provider you’re looking for hasn’t been created yet, see the develop a provider section to learn how to build it yourself.
Once you’ve added a provider as a dependency, it can be registered with OpenFeature like this:
import openfeature
openfeature.set_provider(my_provider())
In some situations, it may be beneficial to register multiple providers in the same application. This is possible using domains, which is covered in more details below.
Targeting
Sometimes, the value of a flag must consider some dynamic criteria about the application or user, such as the user’s location, IP, email address, or the server’s location. In OpenFeature, we refer to this as targeting. If the flag management system you’re using supports targeting, you can provide the input data using the evaluation context.
import gleam/dynamic
import gleam/option.{None}
import openfeature
import openfeature/client
import openfeature/evaluation_context.{EvaluationContext}
// set the global evaluation context
openfeature.set_context(
evaluation_context.targetless([
#("region", dynamic.from("us-east-1-iah-1a")),
])
)
// set the client evaluation context
let my_app_client =
openfeature.get_domain_client("my-app")
|> client.set_context(
evaluation_context.targetless([
#("version", dynamic.from("1.4.6")),
])
)
// set the invocation context
client.get_bool_details(
my_app_client,
"bool-flag",
False,
evaluation_context.targeted(
"userId:1234",
[#("company", dynamic.from("Wise"))]
),
)
Hooks
TODO
Logging
TODO
Domains
Clients can be assigned to a domain. A domain is a logical identifier which can be used to associate clients with a particular provider. If a domain has no associated provider, the default provider is used.
import openfeature
// registering the default provider
openfeature.set_provider(local_provider())
// registering a domain provider
openfeature.set_domain_provider("cached-domain", cached_provider())
// a client bound to the default provider
openfeature.get_client()
// a client bound to the cached provider
openfeature.get_domain_client("cached-domain")
Eventing
TODO
Shutdown
The OpenFeature API provides a close function to perform a cleanup of all registered providers. This should only be called when your application is in the process of shutting down.
import openfeature
openfeature.shutdown()
Extending
Develop a provider
To develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency. This can be a new repository or included in the existing contrib repository available under the OpenFeature organization. You’ll then need to write the provider by exporting a function that returns a value of type FeatureProvider
, exported by the OpenFeature SDK.
import gleam/dynamic.{type Dynamic}
import openfeature/evaluation_context.{type EvaluationContext}
import openfeature/provider.{type FeatureProvider, FeatureProvider}
pub fn my_provider() -> FeatureProvider {
FeatureProvider(
get_metadata: fn() { provider.Metadata("My Provider") },
initialize: fn(evaluation_context: EvaluationContext) {
// code to initialize your provider
todo
},
shutdown: fn() {
// code to shutdown your provider
todo
},
resolve_bool_evaluation: fn(
flag: String,
default_value: Bool,
evaluation_context: EvaluationContext,
) {
// code to evaluate a boolean value
todo
},
resolve_string_evaluation: fn(
flag: String,
default_value: String,
evaluation_context: EvaluationContext,
) {
// code to evaluate a string value
todo
},
resolve_int_evaluation: fn(
flag: String,
default_value: Int,
evaluation_context: EvaluationContext,
) {
// code to evaluate an integer value
todo
},
resolve_float_evaluation: fn(
flag: String,
default_value: Float,
evaluation_context: EvaluationContext,
) {
// code to evaluate a float value
todo
},
resolve_dynamic_evaluation: fn(
flag: String,
default_value: Dynamic,
evaluation_context: EvaluationContext,
) {
// code to evaluate a dynamic value
todo
},
)
}
Develop a hook
TODO