|
| 1 | +# Flagsmith Provider for OpenFeature |
| 2 | + |
| 3 | +A Rust implementation of the OpenFeature provider for Flagsmith, enabling dynamic feature flag evaluation using the Flagsmith platform. |
| 4 | + |
| 5 | +This provider integrates the [Flagsmith Rust SDK](https://github.com/Flagsmith/flagsmith-rust-client) with [OpenFeature](https://openfeature.dev/), supporting both environment-level and identity-specific flag evaluation with trait-based targeting. |
| 6 | + |
| 7 | +## Features |
| 8 | + |
| 9 | +- **Environment-level evaluation**: Evaluate flags at the environment level without user context |
| 10 | +- **Identity-specific evaluation**: Target users with personalized flag values based on traits |
| 11 | +- **Type safety**: Full support for boolean, string, integer, float, and structured (JSON) flag types |
| 12 | +- **Local evaluation**: Optional local evaluation mode for improved performance and offline support |
| 13 | +- **Async support**: Built on Tokio with non-blocking flag evaluations |
| 14 | + |
| 15 | +## Installation |
| 16 | + |
| 17 | +Add the dependency in your `Cargo.toml`: |
| 18 | +```bash |
| 19 | +cargo add open-feature-flagsmith |
| 20 | +cargo add open-feature |
| 21 | +``` |
| 22 | + |
| 23 | +## Basic Usage |
| 24 | + |
| 25 | +```rust |
| 26 | +use open_feature::OpenFeature; |
| 27 | +use open_feature::EvaluationContext; |
| 28 | +use open_feature_flagsmith::{FlagsmithProvider, FlagsmithOptions}; |
| 29 | + |
| 30 | +#[tokio::main] |
| 31 | +async fn main() { |
| 32 | + // Initialize the provider |
| 33 | + let provider = FlagsmithProvider::new( |
| 34 | + "your-environment-key".to_string(), |
| 35 | + FlagsmithOptions::default() |
| 36 | + ).await.unwrap(); |
| 37 | + |
| 38 | + // Set up OpenFeature API |
| 39 | + let mut api = OpenFeature::singleton_mut().await; |
| 40 | + api.set_provider(provider).await; |
| 41 | + let client = api.create_client(); |
| 42 | + |
| 43 | + // Evaluate a flag |
| 44 | + let context = EvaluationContext::default(); |
| 45 | + let enabled = client |
| 46 | + .get_bool_value("my-feature", &context, None) |
| 47 | + .await |
| 48 | + .unwrap_or(false); |
| 49 | + |
| 50 | + println!("Feature enabled: {}", enabled); |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +## Identity-Specific Evaluation |
| 55 | + |
| 56 | +```rust |
| 57 | +use open_feature::EvaluationContext; |
| 58 | + |
| 59 | +// Create context with targeting key and user traits |
| 60 | +let context = EvaluationContext::default() |
| 61 | + .with_targeting_key("user-123") |
| 62 | + .with_custom_field("email", "user@example.com") |
| 63 | + .with_custom_field("plan", "premium") |
| 64 | + .with_custom_field("age", 25); |
| 65 | + |
| 66 | +let enabled = client |
| 67 | + .get_bool_value("premium-feature", &context, None) |
| 68 | + .await |
| 69 | + .unwrap_or(false); |
| 70 | +``` |
| 71 | + |
| 72 | +## Flag Types |
| 73 | + |
| 74 | +```rust |
| 75 | +// Assuming you have set up the client as shown in the Basic Usage section |
| 76 | +let context = EvaluationContext::default(); |
| 77 | + |
| 78 | +// Boolean flags |
| 79 | +let enabled = client.get_bool_value("feature-toggle", &context, None).await.unwrap(); |
| 80 | + |
| 81 | +// String flags |
| 82 | +let theme = client.get_string_value("theme", &context, None).await.unwrap(); |
| 83 | + |
| 84 | +// Integer flags |
| 85 | +let max_items = client.get_int_value("max-items", &context, None).await.unwrap(); |
| 86 | + |
| 87 | +// Float flags |
| 88 | +let multiplier = client.get_float_value("price-multiplier", &context, None).await.unwrap(); |
| 89 | + |
| 90 | +// Structured flags (JSON objects) |
| 91 | +let config = client.get_object_value("config", &context, None).await.unwrap(); |
| 92 | +``` |
| 93 | + |
| 94 | +## Local Evaluation |
| 95 | + |
| 96 | +Local evaluation mode downloads the environment configuration and evaluates flags locally for better performance: |
| 97 | + |
| 98 | +```rust |
| 99 | +use open_feature_flagsmith::FlagsmithOptions; |
| 100 | + |
| 101 | +// Requires a server-side environment key (starts with "ser.") |
| 102 | +let provider = FlagsmithProvider::new( |
| 103 | + "ser.your-server-key".to_string(), |
| 104 | + FlagsmithOptions::default() |
| 105 | + .with_local_evaluation(true) |
| 106 | +).await.unwrap(); |
| 107 | +``` |
| 108 | + |
| 109 | +**Benefits:** |
| 110 | +- Lower latency (no API calls per evaluation) |
| 111 | +- Works offline (uses cached environment) |
| 112 | +- Reduced API load |
| 113 | + |
| 114 | +**Requirements:** |
| 115 | +- Server-side environment key (starts with `ser.`) |
| 116 | +- Initial API call to fetch environment |
| 117 | +- Periodic polling to refresh (default: 60s) |
| 118 | + |
| 119 | +## Configuration Options |
| 120 | + |
| 121 | +Configurations can be provided as constructor options: |
| 122 | + |
| 123 | +| Option | Type | Default | Description | |
| 124 | +|--------|------|---------|-------------| |
| 125 | +| `api_url` | `Option<String>` | Flagsmith Edge API | Custom Flagsmith API endpoint | |
| 126 | +| `request_timeout_seconds` | `Option<u64>` | 10 | Request timeout in seconds | |
| 127 | +| `enable_local_evaluation` | `bool` | `false` | Enable local evaluation mode | |
| 128 | +| `environment_refresh_interval_mills` | `Option<u64>` | 60000 | Polling interval for local mode (ms) | |
| 129 | +| `enable_analytics` | `bool` | `false` | Enable analytics tracking | |
| 130 | +| `custom_headers` | `Option<HeaderMap>` | None | Custom HTTP headers | |
| 131 | + |
| 132 | +### Example Configuration |
| 133 | + |
| 134 | +```rust |
| 135 | +use open_feature_flagsmith::FlagsmithOptions; |
| 136 | + |
| 137 | +let options = FlagsmithOptions::default() |
| 138 | + .with_local_evaluation(true) |
| 139 | + .with_analytics(true) |
| 140 | + .with_timeout(15); |
| 141 | + |
| 142 | +let provider = FlagsmithProvider::new( |
| 143 | + "ser.your-key".to_string(), |
| 144 | + options |
| 145 | +).await.unwrap(); |
| 146 | +``` |
| 147 | + |
| 148 | +## Evaluation Context Transformation |
| 149 | + |
| 150 | +OpenFeature standardizes the evaluation context with a `targeting_key` and arbitrary custom fields. For Flagsmith: |
| 151 | + |
| 152 | +- **`targeting_key`** → Flagsmith identity identifier |
| 153 | +- **`custom_fields`** → Flagsmith traits for segmentation |
| 154 | + |
| 155 | +When a `targeting_key` is present, the provider performs identity-specific evaluation. Otherwise, it evaluates at the environment level. |
| 156 | + |
| 157 | +## License |
| 158 | + |
| 159 | +Apache 2.0 - See [LICENSE](./../../LICENSE) for more information. |
0 commit comments