### Initialize GrowthBookClient with Builder Source: https://context7.com/growthbook/growthbook-rust/llms.txt Use the GrowthBookClientBuilder to create a client instance with customizable options like API URL, SDK key, caching, and attributes. This example demonstrates setting global attributes and enabling auto-refresh. ```rust use growthbook_rust::client::GrowthBookClientBuilder; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use std::collections::HashMap; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { // Create client with full configuration let mut global_attrs = HashMap::new(); global_attrs.insert( "tenantId".to_string(), GrowthBookAttribute::new("tenantId".to_string(), GrowthBookAttributeValue::String("acme-corp".to_string())) ); let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .ttl(Duration::from_secs(60)) // Cache features for 60 seconds .auto_refresh(true) // Enable background feature updates .refresh_interval(Duration::from_secs(30)) // Refresh every 30 seconds .attributes(global_attrs) // Set global targeting attributes .build() .await?; println!("GrowthBook client initialized with {} features", client.total_features()); Ok(()) } ``` -------------------------------- ### Get Detailed Feature Result in Rust Source: https://context7.com/growthbook/growthbook-rust/llms.txt Use `feature_result` to retrieve a detailed `FeatureResult` object. This includes the feature value, on/off state, evaluation source, and experiment details. It supports type-safe extraction of values for strings and complex JSON objects. ```rust use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use serde::Deserialize; #[derive(Deserialize, Debug)] struct ButtonConfig { color: String, size: String, text: String, } #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .build() .await?; let user_attrs = vec![ GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("user-789".to_string())), ]; // Get detailed feature result let result = client.feature_result("checkout-button-config", Some(user_attrs)); println!("Feature value: {:?}", result.value); println!("Is on: {}", result.on); println!("Is off: {}", result.off); println!("Source: {}", result.source); // "defaultValue", "force", "experiment", "unknownFeature" // Check if user is in an experiment if let Some(exp_result) = &result.experiment_result { println!("In experiment: {}", exp_result.in_experiment); println!("Variation ID: {}", exp_result.variation_id); println!("Experiment key: {}", exp_result.key); } // Type-safe value extraction for string features if let Ok(banner_text) = result.value_as::() { println!("Banner text: {}", banner_text); } // Type-safe extraction for complex JSON objects let config_result = client.feature_result("button-config", None); match config_result.value_as::() { Ok(config) => { println!("Button color: {}, size: {}, text: {}", config.color, config.size, config.text); } Err(e) => { println!("Failed to parse config: {}", e); } } Ok(()) } ``` -------------------------------- ### Initialize GrowthBook Client with Environment Variables Source: https://context7.com/growthbook/growthbook-rust/llms.txt Initialize the GrowthBook client using the builder pattern. If `api_url` and `client_key` are not explicitly set, the SDK defaults to using the `GB_URL` and `GB_SDK_KEY` environment variables. ```rust use growthbook_rust::client::GrowthBookClientBuilder; #[tokio::main] async fn main() -> Result<(), Box> { // When api_url and client_key are not set in builder, // the SDK falls back to GB_URL and GB_SDK_KEY environment variables let client = GrowthBookClientBuilder::new() .auto_refresh(true) .build() .await?; println!("Client initialized from environment variables"); Ok(()) } ``` -------------------------------- ### Initialize GrowthBook Client Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Use the GrowthBookClientBuilder to configure the client with API settings, caching, and auto-refresh intervals. ```rust use growthbook_rust::client::GrowthBookClientBuilder; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-key".to_string()) .ttl(Duration::from_secs(60)) // Cache TTL .auto_refresh(true) // Enable background updates .refresh_interval(Duration::from_secs(30)) .build() .await?; Ok(()) } ``` -------------------------------- ### Configure SDK via Environment Variables Source: https://context7.com/growthbook/growthbook-rust/llms.txt Set environment variables to provide fallback configuration values for the SDK. ```bash # Set GrowthBook API URL export GB_URL="https://cdn.growthbook.io" ``` -------------------------------- ### GrowthBookClientBuilder::new Source: https://context7.com/growthbook/growthbook-rust/llms.txt Demonstrates how to create and configure a GrowthBookClient using the builder pattern, including setting API URL, client key, caching, auto-refresh, and global attributes. ```APIDOC ## GrowthBookClientBuilder::new ### Description Creates a new builder instance for configuring and constructing a GrowthBookClient with customizable options including API endpoint, SDK key, caching, auto-refresh, callbacks, and sticky bucketing. ### Method Builder pattern ### Endpoint N/A (Client-side SDK) ### Parameters #### Query Parameters N/A #### Request Body N/A ### Request Example ```rust use growthbook_rust::client::GrowthBookClientBuilder; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use std::collections::HashMap; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { // Create client with full configuration let mut global_attrs = HashMap::new(); global_attrs.insert( "tenantId".to_string(), GrowthBookAttribute::new("tenantId".to_string(), GrowthBookAttributeValue::String("acme-corp".to_string())) ); let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .ttl(Duration::from_secs(60)) // Cache features for 60 seconds .auto_refresh(true) // Enable background feature updates .refresh_interval(Duration::from_secs(30)) // Refresh every 30 seconds .attributes(global_attrs) // Set global targeting attributes .build() .await?; println!("GrowthBook client initialized with {} features", client.total_features()); Ok(()) } ``` ### Response #### Success Response (200) N/A (Builder pattern, returns a configured client) #### Response Example N/A ``` -------------------------------- ### Set SDK Client Key and HTTP Timeout Source: https://context7.com/growthbook/growthbook-rust/llms.txt Configure the GrowthBook SDK using environment variables for the client key and HTTP client timeout. The default timeout is 10 seconds. ```bash export GB_SDK_KEY="sdk-abc123" # HTTP client timeout in seconds (default: 10) export GB_HTTP_CLIENT_TIMEOUT="15" # Auto-refresh interval in seconds (default: 60) export GB_UPDATE_INTERVAL="30" ``` -------------------------------- ### Configure Default In-Memory Sticky Bucketing Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Use the built-in InMemoryStickyBucketService for non-persistent sticky bucketing requirements. ```rust use std::sync::Arc; use growthbook_rust::sticky_bucket::InMemoryStickyBucketService; let sticky_service = Arc::new(InMemoryStickyBucketService::new()); let client = GrowthBookClientBuilder::new() .api_url(api_url) .client_key(sdk_key) .sticky_bucket_service(sticky_service) .build() .await?; ``` -------------------------------- ### Initialize GrowthBook with Decryption Key Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Provide a decryption key to the builder when using encrypted features. ```rust let client = GrowthBookClientBuilder::new() .api_url(api_url) .client_key(sdk_key) .decryption_key("your-decryption-key".to_string()) .build() .await?; ``` -------------------------------- ### Implement Sticky Bucketing with InMemoryStickyBucketService Source: https://context7.com/growthbook/growthbook-rust/llms.txt Use the in-memory service to ensure users remain in the same experiment variation across sessions. This is suitable for testing or simple applications. ```rust use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use growthbook_rust::sticky_bucket::InMemoryStickyBucketService; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use std::sync::Arc; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { // Create in-memory sticky bucket service (for testing/simple use cases) let sticky_service = Arc::new(InMemoryStickyBucketService::new()); let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .sticky_bucket_service(sticky_service) .auto_refresh(true) .refresh_interval(Duration::from_secs(60)) .build() .await?; // User will be consistently assigned to the same variation let user_attrs = vec![ GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("user-123".to_string())), ]; // First evaluation - user gets assigned to a variation let result1 = client.feature_result("checkout-experiment", Some(user_attrs.clone())); println!("First evaluation - Variation: {:?}", result1.value); // Subsequent evaluations return the same variation due to sticky bucketing let result2 = client.feature_result("checkout-experiment", Some(user_attrs.clone())); println!("Second evaluation - Variation: {:?}", result2.value); if let Some(exp) = &result2.experiment_result { println!("Sticky bucket used: {}", exp.sticky_bucket_used); } Ok(()) } ``` -------------------------------- ### Handle GrowthBook SDK Errors Source: https://context7.com/growthbook/growthbook-rust/llms.txt Demonstrates how to catch and inspect GrowthbookError codes during client initialization using the GrowthBookClientBuilder. ```rust use growthbook_rust::client::GrowthBookClientBuilder; use growthbook_rust::error::{GrowthbookError, GrowthbookErrorCode}; #[tokio::main] async fn main() { // Example: Missing required configuration let result = GrowthBookClientBuilder::new() .auto_refresh(false) // Missing both api_url/client_key AND manual features .build() .await; match result { Ok(client) => { println!("Client created with {} features", client.total_features()); } Err(e) => { println!("Error code: {:?}", e.code); println!("Error message: {}", e.message); match e.code { GrowthbookErrorCode::ConfigError => { println!("Configuration error - provide api_url/client_key or manual features"); } GrowthbookErrorCode::GrowthbookGateway => { println!("Network error - check API URL and connectivity"); } GrowthbookErrorCode::ParseError => { println!("Parse error - check feature JSON format"); } _ => { println!("Other error occurred"); } } } } // Valid configuration example let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .build() .await .expect("Failed to create GrowthBook client"); println!("Successfully created client"); } ``` -------------------------------- ### Add GrowthBook Rust SDK to Cargo.toml Source: https://context7.com/growthbook/growthbook-rust/llms.txt Include the GrowthBook Rust SDK and necessary dependencies in your project's Cargo.toml file. ```toml [dependencies] growthbook-rust = "0.1.1" tokio = { version = "1.38.0", features = ["full"] } serde_json = "1.0" ``` -------------------------------- ### Implement Custom Sticky Bucket Service Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Implement the StickyBucketService trait to enable durable storage for sticky bucketing in production environments. ```rust use std::collections::HashMap; use growthbook_rust::sticky_bucket::StickyBucketService; use growthbook_rust::model_public::GrowthBookAttribute; #[derive(Debug)] pub struct MyRedisStickyBucketService { // ... connection pool etc. } impl StickyBucketService for MyRedisStickyBucketService { fn get_assignments(&self, attribute_name: &str, attribute_value: &str) -> Option> { // Fetch from Redis usually returning Key (experiment_key) -> Value (variation_key) // ... None } fn save_assignments(&self, attribute_name: &str, attribute_value: &str, assignments: HashMap) { // Write to Redis // ... } fn get_all_assignments(&self, attributes: &HashMap) -> HashMap { // Batch fetch all assignments for the given user attributes HashMap::new() } } ``` -------------------------------- ### Check Features and Values Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Evaluate feature flags or retrieve typed configuration values from the client. ```rust // Simple check if client.is_on("my-feature", None) { println!("Feature is enabled!"); } // Get typed value let value = client.feature_result("my-config", None).value_as::()?; ``` -------------------------------- ### Initialize Offline Mode with Manual Features Source: https://context7.com/growthbook/growthbook-rust/llms.txt Use this pattern to load features from local sources or files. Disable auto-refresh to prevent the SDK from attempting network requests. ```rust use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use serde_json::json; #[tokio::main] async fn main() -> Result<(), Box> { // Define features manually (e.g., loaded from a file or embedded) let features_json = json!({ "dark-mode": { "defaultValue": true }, "pricing-tier": { "defaultValue": "standard", "rules": [ { "condition": { "isPremium": true }, "force": "premium" } ] }, "max-upload-size": { "defaultValue": 10, "rules": [ { "condition": { "plan": "enterprise" }, "force": 100 }, { "condition": { "plan": "pro" }, "force": 50 } ] }, "button-config": { "defaultValue": { "color": "blue", "text": "Submit" } } }); // Build client in offline mode with manual features let client = GrowthBookClientBuilder::new() .auto_refresh(false) // Disable network fetching .features_json(features_json)? .build() .await?; println!("Loaded {} features in offline mode", client.total_features()); // Use features normally if client.is_on("dark-mode", None) { println!("Dark mode enabled"); } let result = client.feature_result("pricing-tier", None); println!("Pricing tier: {:?}", result.value); // Manual refresh is still available if you update features later // client.refresh().await; Ok(()) } ``` -------------------------------- ### Configure Encrypted Feature Support Source: https://context7.com/growthbook/growthbook-rust/llms.txt Provide a decryption key to the builder to enable transparent decryption of AES-CBC encrypted feature payloads from the GrowthBook API. ```rust use growthbook_rust::client::GrowthBookClientBuilder; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { // The decryption key is provided by GrowthBook when encryption is enabled let decryption_key = "your-base64-encoded-decryption-key"; let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .decryption_key(decryption_key.to_string()) .ttl(Duration::from_secs(60)) .build() .await?; // Features are automatically decrypted when fetched // Use them normally - decryption is transparent println!("Encrypted features loaded: {}", client.total_features()); Ok(()) } ``` -------------------------------- ### Implement Custom StickyBucketService in Rust Source: https://context7.com/growthbook/growthbook-rust/llms.txt Use this trait implementation to persist user experiment assignments in external databases like Redis. ```rust use growthbook_rust::sticky_bucket::StickyBucketService; use growthbook_rust::model_public::GrowthBookAttribute; use growthbook_rust::client::GrowthBookClientBuilder; use std::collections::HashMap; use std::sync::Arc; #[derive(Debug)] pub struct RedisStickyBucketService { // redis_client: redis::Client, } impl RedisStickyBucketService { pub fn new(/* redis_url: &str */) -> Self { Self { // redis_client: redis::Client::open(redis_url).unwrap(), } } fn make_key(&self, attribute_name: &str, attribute_value: &str) -> String { format!("gb:sticky:{}:{}", attribute_name, attribute_value) } } impl StickyBucketService for RedisStickyBucketService { fn get_assignments( &self, attribute_name: &str, attribute_value: &str, ) -> Option> { let _key = self.make_key(attribute_name, attribute_value); // Fetch from Redis: HGETALL key // let mut conn = self.redis_client.get_connection().unwrap(); // let result: HashMap = conn.hgetall(&key).unwrap_or_default(); // if result.is_empty() { None } else { Some(result) } None // Placeholder } fn save_assignments( &self, attribute_name: &str, attribute_value: &str, assignments: HashMap, ) { let _key = self.make_key(attribute_name, attribute_value); // Save to Redis: HSET key field value [field value ...] // let mut conn = self.redis_client.get_connection().unwrap(); // for (exp_key, variation) in assignments { // let _: () = conn.hset(&key, exp_key, variation).unwrap(); // } let _ = assignments; // Placeholder } fn get_all_assignments( &self, attributes: &HashMap, ) -> HashMap { let mut all = HashMap::new(); for (attr_name, attr) in attributes { if let Some(assignments) = self.get_assignments(attr_name, &attr.value.to_string()) { all.extend(assignments); } } all } } #[tokio::main] async fn main() -> Result<(), Box> { let redis_sticky = Arc::new(RedisStickyBucketService::new()); let _client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .sticky_bucket_service(redis_sticky) .build() .await?; Ok(()) } ``` -------------------------------- ### Subscribe to Tracking Callbacks Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Register callbacks to handle feature usage and experiment impression events. ```rust let client = GrowthBookClientBuilder::new() // ... .on_feature_usage(Box::new(|key, result| { println!("Feature '{}' evaluated: {:?}", key, result.value); })) .on_experiment_viewed(Box::new(|experiment_result| { // Track experiment impression println!("Experiment viewed: {}", experiment_result.key); })) .build() .await?; ``` -------------------------------- ### Manage Context and Attributes Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Define global attributes for all evaluations and provide per-check overrides. ```rust use std::collections::HashMap; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; // Global attributes let mut global_attrs = HashMap::new(); global_attrs.insert("tenantId".to_string(), GrowthBookAttributeValue::String("123".to_string())); let client = GrowthBookClientBuilder::new() .api_url(api_url) .client_key(sdk_key) .attributes(global_attrs) .build() .await?; // Per-check attributes (merged with global) let mut user_attrs = Vec::new(); user_attrs.push(GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("456".to_string()))); if client.is_on("my-feature", Some(user_attrs)) { // ... } ``` -------------------------------- ### GrowthBookClientTrait::is_on Source: https://context7.com/growthbook/growthbook-rust/llms.txt Checks if a feature flag is enabled for the current user context. Supports optional user attributes for targeting evaluation. ```APIDOC ## GrowthBookClientTrait::is_on ### Description Checks if a feature flag is enabled for the current user context. Returns `true` if the feature is on, `false` otherwise. Accepts optional user attributes that are merged with global attributes for targeting evaluation. ### Method GET (Conceptual, client-side evaluation) ### Endpoint N/A (Client-side SDK) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example ```rust use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .build() .await?; // Simple feature check without attributes if client.is_on("dark-mode", None) { println!("Dark mode is enabled globally"); } // Feature check with user-specific attributes for targeting let user_attrs = vec![ GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("user-456".to_string())), GrowthBookAttribute::new("country".to_string(), GrowthBookAttributeValue::String("US".to_string())), GrowthBookAttribute::new("isPremium".to_string(), GrowthBookAttributeValue::Bool(true)), ]; if client.is_on("premium-feature", Some(user_attrs)) { println!("Premium feature enabled for this user"); } else { println!("Premium feature not available"); } // Check if feature is explicitly off if client.is_off("deprecated-feature", None) { println!("Deprecated feature is disabled"); } Ok(()) } ``` ### Response #### Success Response (200) - **boolean** (bool) - `true` if the feature is enabled, `false` otherwise. #### Response Example ```json true ``` ``` -------------------------------- ### Create and Use GrowthBook Attributes Source: https://context7.com/growthbook/growthbook-rust/llms.txt Define user attributes for targeting rules and experiment bucketing. Attributes can be of various types including strings, numbers, booleans, arrays, and nested objects. Attributes can be created individually or parsed from JSON. ```rust use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use std::collections::HashMap; #[tokio::main] async fn main() -> Result<(), Box> { // Create individual attributes let user_id = GrowthBookAttribute::new( "userId".to_string(), GrowthBookAttributeValue::String("user-12345".to_string()) ); let age = GrowthBookAttribute::new( "age".to_string(), GrowthBookAttributeValue::Int(28) ); let account_balance = GrowthBookAttribute::new( "accountBalance".to_string(), GrowthBookAttributeValue::Float(1234.56) ); let is_premium = GrowthBookAttribute::new( "isPremium".to_string(), GrowthBookAttributeValue::Bool(true) ); // Array attribute for multi-value targeting let tags = GrowthBookAttribute::new( "tags".to_string(), GrowthBookAttributeValue::Array(vec![ GrowthBookAttributeValue::String("vip".to_string()), GrowthBookAttributeValue::String("early-adopter".to_string()), ]) ); // Nested object attribute let device = GrowthBookAttribute::new( "device".to_string(), GrowthBookAttributeValue::Object(vec![ GrowthBookAttribute::new("type".to_string(), GrowthBookAttributeValue::String("mobile".to_string())), GrowthBookAttribute::new("os".to_string(), GrowthBookAttributeValue::String("iOS".to_string())), ]) ); // Use attributes for feature evaluation let user_attrs = vec![user_id, age, account_balance, is_premium, tags, device]; let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .build() .await?; let result = client.feature_result("personalized-offer", Some(user_attrs)); println!("Offer for user: {:?}", result.value); // Create attributes from JSON using GrowthBookAttribute::from() let json_attrs = serde_json::json!({ "userId": "user-999", "country": "US", "beta": true }); let attrs_from_json = GrowthBookAttribute::from(json_attrs)?; let result2 = client.feature_result("beta-feature", Some(attrs_from_json)); println!("Beta feature: {:?}", result2.value); Ok(()) } ``` -------------------------------- ### Event Callbacks (on_feature_usage, on_experiment_viewed) Source: https://context7.com/growthbook/growthbook-rust/llms.txt Register callback functions to track feature usage and experiment impressions. These callbacks are automatically invoked when features are evaluated or when users are bucketed into experiments, enabling integration with analytics and event tracking systems. ```APIDOC ## Event Callbacks (on_feature_usage, on_experiment_viewed) ### Description Register callback functions to track feature usage and experiment impressions for analytics and event tracking systems. These callbacks fire automatically when features are evaluated or when users are bucketed into experiments. ### Method - `on_feature_usage(callback: Box)` - `on_experiment_viewed(callback: Box)` - `add_on_refresh(callback: Box)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use growthbook_rust::client::GrowthBookClientBuilder; use growthbook_rust::model_public::{FeatureResult, ExperimentResult}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .on_feature_usage(Box::new(|feature_key: String, result: FeatureResult| { // Track feature usage in your analytics system println!("Feature evaluated: {}", feature_key); println!(" Value: {:?}", result.value); println!(" Source: {}", result.source); // Example: Send to analytics // analytics.track("feature_evaluated", json!({ // "feature": feature_key, // "value": result.value, // "source": result.source // })); })) .on_experiment_viewed(Box::new(|exp_result: ExperimentResult| { // Track experiment impressions for A/B test analysis println!("Experiment impression:"); println!(" Feature ID: {}", exp_result.feature_id); println!(" Experiment key: {}", exp_result.key); println!(" Variation ID: {}", exp_result.variation_id); println!(" In experiment: {}", exp_result.in_experiment); println!(" Hash attribute: {:?}", exp_result.hash_attribute); // Example: Send to experiment tracking // experiments.track_impression( // exp_result.key, // exp_result.variation_id, // exp_result.hash_value // ); })) .add_on_refresh(Box::new(|| { // Called when features are refreshed from the server println!("Features refreshed from GrowthBook API"); })) .build() .await?; Ok(()) } ``` ### Response #### Success Response (200) Callbacks do not return a value in the traditional sense but execute side effects (e.g., sending data to an analytics service). #### Response Example No direct response example as these are callbacks. ``` -------------------------------- ### Register Event Callbacks in Rust Source: https://context7.com/growthbook/growthbook-rust/llms.txt Implement `on_feature_usage` and `on_experiment_viewed` callbacks to track feature evaluations and experiment impressions. These callbacks are automatically invoked during feature evaluation and experiment bucketing, allowing integration with analytics systems. ```rust use growthbook_rust::client::GrowthBookClientBuilder; use growthbook_rust::model_public::{FeatureResult, ExperimentResult}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .on_feature_usage(Box::new(|feature_key: String, result: FeatureResult| { // Track feature usage in your analytics system println!("Feature evaluated: {}", feature_key); println!(" Value: {:?}", result.value); println!(" Source: {}", result.source); // Example: Send to analytics // analytics.track("feature_evaluated", json!({ // "feature": feature_key, // "value": result.value, // "source": result.source // })); })) .on_experiment_viewed(Box::new(|exp_result: ExperimentResult| { // Track experiment impressions for A/B test analysis println!("Experiment impression:"); println!(" Feature ID: {}", exp_result.feature_id); println!(" Experiment key: {}", exp_result.key); println!(" Variation ID: {}", exp_result.variation_id); println!(" In experiment: {}", exp_result.in_experiment); println!(" Hash attribute: {:?}", exp_result.hash_attribute); // Example: Send to experiment tracking // experiments.track_impression( // exp_result.key, // exp_result.variation_id, // exp_result.hash_value // ); })) .add_on_refresh(Box::new(|| { // Called when features are refreshed from the server println!("Features refreshed from GrowthBook API"); })) .build() .await?; Ok(()) } ``` -------------------------------- ### Manual Feature Management Source: https://github.com/growthbook/growthbook-rust/blob/main/README.md Disable auto-refresh to manually provide feature definitions and trigger updates. ```rust use serde_json::json; let features_json = json!({ "my-feature": { "defaultValue": true } }); let client = GrowthBookClientBuilder::new() .api_url(api_url) .client_key(sdk_key) .auto_refresh(false) // Disable background sync .features_json(features_json)? // Set features manually .build() .await?; // You can manually refresh features later client.refresh().await; ``` -------------------------------- ### Check Feature Flag Status with GrowthBookClient Source: https://context7.com/growthbook/growthbook-rust/llms.txt Utilize the GrowthBookClientTrait to check if a feature flag is enabled or disabled. This method supports checking with and without user-specific attributes for targeting. ```rust use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .build() .await?; // Simple feature check without attributes if client.is_on("dark-mode", None) { println!("Dark mode is enabled globally"); } // Feature check with user-specific attributes for targeting let user_attrs = vec![ GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("user-456".to_string())), GrowthBookAttribute::new("country".to_string(), GrowthBookAttributeValue::String("US".to_string())), GrowthBookAttribute::new("isPremium".to_string(), GrowthBookAttributeValue::Bool(true)), ]; if client.is_on("premium-feature", Some(user_attrs)) { println!("Premium feature enabled for this user"); } else { println!("Premium feature not available"); } // Check if feature is explicitly off if client.is_off("deprecated-feature", None) { println!("Deprecated feature is disabled"); } Ok(()) } ``` -------------------------------- ### Implement Custom FeatureCache in Rust Source: https://context7.com/growthbook/growthbook-rust/llms.txt Implement this trait to replace the default in-memory cache with external systems like Redis or Memcached. ```rust use growthbook_rust::cache::{FeatureCache, BoxFuture}; use growthbook_rust::dto::GrowthBookResponse; use growthbook_rust::client::GrowthBookClientBuilder; use std::sync::Arc; pub struct RedisFeatureCache { // client: redis::Client, ttl_seconds: u64, } impl RedisFeatureCache { pub fn new(/* redis_url: &str, */ ttl_seconds: u64) -> Self { Self { // client: redis::Client::open(redis_url).unwrap(), ttl_seconds, } } } impl FeatureCache for RedisFeatureCache { fn get(&self, key: &str) -> BoxFuture<'_, Option> { let _key = key.to_string(); Box::pin(async move { // let mut conn = self.client.get_async_connection().await.unwrap(); // let data: Option = conn.get(&key).await.unwrap(); // data.and_then(|s| serde_json::from_str(&s).ok()) None // Placeholder }) } fn set(&self, key: &str, value: GrowthBookResponse) -> BoxFuture<'_, ()> { let _key = key.to_string(); let _ttl = self.ttl_seconds; let _value = value; Box::pin(async move { // let mut conn = self.client.get_async_connection().await.unwrap(); // let json = serde_json::to_string(&value).unwrap(); // let _: () = conn.set_ex(&key, json, ttl).await.unwrap(); }) } } #[tokio::main] async fn main() -> Result<(), Box> { let redis_cache = Arc::new(RedisFeatureCache::new(/* "redis://127.0.0.1/", */ 300)); let _client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .cache(redis_cache) .build() .await?; Ok(()) } ``` -------------------------------- ### GrowthBookClientTrait::feature_result Source: https://context7.com/growthbook/growthbook-rust/llms.txt Retrieves a detailed `FeatureResult` object for a given feature key and optional user attributes. This result includes the feature's value, on/off state, evaluation source, and experiment details if applicable. It also provides methods for type-safe value extraction. ```APIDOC ## GrowthBookClientTrait::feature_result ### Description Returns a detailed `FeatureResult` containing the feature value, on/off state, source of the evaluation, and experiment information if applicable. Use this when you need the actual value of a feature flag rather than just a boolean check. ### Method `feature_result(feature_key: &str, attributes: Option>) -> FeatureResult` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use growthbook_rust::client::{GrowthBookClientBuilder, GrowthBookClientTrait}; use growthbook_rust::model_public::{GrowthBookAttribute, GrowthBookAttributeValue}; use serde::Deserialize; #[derive(Deserialize, Debug)] struct ButtonConfig { color: String, size: String, text: String, } #[tokio::main] async fn main() -> Result<(), Box> { let client = GrowthBookClientBuilder::new() .api_url("https://cdn.growthbook.io".to_string()) .client_key("sdk-abc123".to_string()) .build() .await?; let user_attrs = vec![ GrowthBookAttribute::new("userId".to_string(), GrowthBookAttributeValue::String("user-789".to_string())), ]; // Get detailed feature result let result = client.feature_result("checkout-button-config", Some(user_attrs)); println!("Feature value: {:?}", result.value); println!("Is on: {}", result.on); println!("Is off: {}", result.off); println!("Source: {}", result.source); // "defaultValue", "force", "experiment", "unknownFeature" // Check if user is in an experiment if let Some(exp_result) = &result.experiment_result { println!("In experiment: {}", exp_result.in_experiment); println!("Variation ID: {}", exp_result.variation_id); println!("Experiment key: {}", exp_result.key); } // Type-safe value extraction for string features if let Ok(banner_text) = result.value_as::() { println!("Banner text: {}", banner_text); } // Type-safe extraction for complex JSON objects let config_result = client.feature_result("button-config", None); match config_result.value_as::() { Ok(config) => { println!("Button color: {}, size: {}, text: {}", config.color, config.size, config.text); } Err(e) => { println!("Failed to parse config: {}", e); } } Ok(()) } ``` ### Response #### Success Response (200) - **value** (any) - The evaluated value of the feature flag. - **on** (bool) - True if the feature is enabled, false otherwise. - **off** (bool) - True if the feature is disabled, false otherwise. - **source** (string) - The source of the feature evaluation (e.g., "defaultValue", "force", "experiment", "unknownFeature"). - **experiment_result** (ExperimentResult | null) - Details about the experiment the user was included in, if any. #### Response Example ```json { "value": { "color": "blue", "size": "medium", "text": "Click Me" }, "on": true, "off": false, "source": "experiment", "experiment_result": { "in_experiment": true, "variation_id": 1, "key": "button-color-experiment", "feature_id": "checkout-button-config", "hash_attribute": "userId", "hash_value": "some_hash_value" } } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.