An open API service indexing awesome lists of open source software.

https://github.com/open-feature/elixir-sdk

Elixir SDK for OpenFeature
https://github.com/open-feature/elixir-sdk

elixir openfeature sdk

Last synced: 10 months ago
JSON representation

Elixir SDK for OpenFeature

Awesome Lists containing this project

README

          




OpenFeature Logo

OpenFeature Elixir SDK



Specification


Release





Docs


License


CI


CII Best Practices

[OpenFeature](https://openfeature.dev) is an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool or in-house solution.

## 🚀 Quick start

### Requirements

It requires Elixir 1.14 or greater to run.

### Install

The package can be installed by adding `open_feature` to your list of dependencies
in `mix.exs`:

```elixir
def deps do
[{:open_feature, "~> 0.1"}]
end
```

### Usage

```elixir
provider = %OpenFeature.Provider.InMemory{
flags: %{
"v2_enabled" => %{
disabled: false,
default_variant: "on",
variants: %{
"on" => true,
"off" => false,
}
}
}
}
{:ok, provider} = OpenFeature.set_provider(provider)
client = OpenFeature.get_client()
v2_enabled = OpenFeature.Client.get_boolean_value(client, "v2_enabled", false)
```

### API Reference

For details, including API documentation, see the respective [Hex docs](https://hexdocs.pm/open_feature/).

## 🌟 Features

| Status | Features | Description |
| ------ | --------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ⚠️ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
| ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
| ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
| ✅ | [Logging](#logging) | Integrate with popular logging packages. |
| ✅ | [Domains](#domains) | Logically bind clients with providers. |
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers. |

Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌

### Providers

[Providers](https://openfeature.dev/docs/reference/concepts/provider) are an abstraction between a flag management system and the OpenFeature SDK.
Look [here](https://openfeature.dev/ecosystem?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Provider&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=Elixir) for a complete list of available providers.
If the provider you're looking for hasn't been created yet, see the [develop a provider](#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:

```elixir
provider = %OpenFeature.Provider.InMemory{
flags: %{
"v2_enabled" => %{
disabled: false,
default_variant: "one",
variants: %{
"on" => true,
"off" => false
}
}
}
}
{:ok, provider} = OpenFeature.set_provider(provider)
```

In some situations, it may be beneficial to register multiple providers in the same application.
This is possible using [domains](#domain), which is covered in more detail 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](https://openfeature.dev/specification/glossary#targeting).
If the flag management system you're using supports targeting, you can provide the input data using the [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context).

```elixir
# set a value to the global context
OpenFeature.set_global_context(%{region: "us-east-1"})

# set a value to the client context
client = OpenFeature.get_client() |> OpenFeature.Client.set_context(%{region: "us-east-1"})

# set a value to the invocation context
flag_value = OpenFeature.Client.get_boolean_value(client, "some-flag", flag, context: %{region: "us-east-1"})
```

### Hooks

[Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle.
Look [here](https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Hook&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=Elixir) for a complete list of available hooks.

Once you've added a hook as a dependency, it can be registered at the client or flag invocation level.

```elixir
## add a hook on this client, to run on all evaluations made by this client
client = OpenFeature.Client.add_hooks(client, [%OpenFeature.Hook{}])

## add a hook for this evaluation only
flag_value = OpenFeature.Client.get_boolean_value(client, flag_key, false, hooks: [%OpenFeature.Hook{}]);
```

### Logging

The Elixir SDK uses the default Elixir Logger.

### 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.

```elixir
provider = %OpenFeature.Provider.InMemory{
flags: %{
"v2_enabled" => %{
disabled: false,
default_variant: "default",
variants: %{
"default" => true
}
}
}
}

# registering the default provider
{:ok, _provider} = OpenFeature.set_provider(provider)
# registering a provider to a domain
{:ok, _provider} = OpenFeature.set_provider("my-domain", provider)

# A client bound to the default provider
default_client = OpenFeature.get_client()
# A client bound to the CachedProvider provider
domain_client = OpenFeature.get_client("my-domain")
```

### Eventing

Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions.
Initialization events (`PROVIDER_READY` on success, `PROVIDER_ERROR` on failure) are dispatched for every provider.
Some providers support additional events, such as `PROVIDER_CONFIGURATION_CHANGED`.

Please refer to the documentation of the provider you're using to see what events are supported.

```elixir
# add an event handler to a client
OpenFeature.Client.add_event_handler(client, :configuration_changed, fn event_details ->
# do something when the provider's flag settings change
end)
```

### 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.

```elixir
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](https://github.com/open-feature/elixir-sdk-contrib) available under the OpenFeature organization.
You’ll then need to write the provider by implementing the `OpenFeature.Provider` behaviour exported by the OpenFeature SDK.

```elixir
defmodule OpenFeature.Provider.NoOp do
alias OpenFeature.ResolutionDetails

@behaviour OpenFeature.Provider

defstruct name: "NoOp", domain: nil, state: :not_ready, hooks: []

def initialize(provider, domain, _evaluation_context), do: {:ok, %{provider | state: :ready, domain: domain}}
def shutdown(_provider), do: :ok

def resolve_boolean_value(_provider, _key, default, _context), do: {:ok, %ResolutionDetails{value: default}}
def resolve_string_value(_provider, _key, default, _context), do: {:ok, %ResolutionDetails{value: default}}
def resolve_number_value(_provider, _key, default, _context), do: {:ok, %ResolutionDetails{value: default}}
def resolve_map_value(_provider, _key, default, _context), do: {:ok, %ResolutionDetails{value: default}}
end

```

> Built a new provider? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=provider&projects=&template=document-provider.yaml&title=%5BProvider%5D%3A+) so we can add it to the docs!

## ⭐️ Support the project

- Give this repo a ⭐️!
- Follow us on social media:
- Twitter: [@openfeature](https://twitter.com/openfeature)
- LinkedIn: [OpenFeature](https://www.linkedin.com/company/openfeature/)
- Join us on [Slack](https://cloud-native.slack.com/archives/C0344AANLA1)
- For more, check out our [community page](https://openfeature.dev/community/)

## 🤝 Contributing

Interested in contributing? Great, we'd love your help! To get started, take a look at the [CONTRIBUTING](CONTRIBUTING.md) guide.

### Thanks to everyone who has already contributed


Pictures of the folks who have contributed to the project

Made with [contrib.rocks](https://contrib.rocks).