Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .sampo/changesets/evaluate-flags-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
cargo/posthog-rs: minor
---

Add `evaluate_flags(distinct_id, options)` for single-call snapshot-based feature flag evaluation. Returns a `FeatureFlagEvaluations` whose `is_enabled` / `get_flag` / `get_flag_payload` methods read from the cached evaluation. `is_enabled` and `get_flag` fire deduplicated `$feature_flag_called` events with full metadata (`$feature_flag_id`, `$feature_flag_version`, `$feature_flag_reason`, `$feature_flag_request_id`). Pass the snapshot to `Event::with_flags(&snapshot)` to attach `$feature/<key>` and `$active_feature_flags` to a captured event without an extra `/flags` call.
69 changes: 69 additions & 0 deletions examples/evaluate_flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/// Snapshot-based feature flag evaluation
///
/// Demonstrates the `evaluate_flags()` API: one round-trip to PostHog produces a
/// `FeatureFlagEvaluations` cache that you can read many times without further
/// network traffic. Reads through `is_enabled` / `get_flag` fire a deduplicated
/// `$feature_flag_called` event with full metadata. Pass the snapshot to
/// `Event::with_flags(&snapshot)` so a captured event inherits `$feature/<key>`
/// and `$active_feature_flags` without a second `/flags` round-trip.
///
/// Run:
/// export POSTHOG_API_TOKEN=phc_your_key
/// cargo run --example evaluate_flags --features async-client
use posthog_rs::{EvaluateFlagsOptions, Event};

#[cfg(feature = "async-client")]
#[tokio::main]
async fn main() {
let api_key = std::env::var("POSTHOG_API_TOKEN").unwrap_or_else(|_| {
println!("No POSTHOG_API_TOKEN found. Demo mode — calls will fail without a key.\n");
"demo_api_key".to_string()
});

let client = posthog_rs::client(api_key.as_str()).await;

let user_id = "user-123";

let snapshot = match client
.evaluate_flags(user_id, EvaluateFlagsOptions::default())
.await
{
Ok(s) => s,
Err(e) => {
println!("evaluate_flags failed: {e}");
return;
}
};

println!("Loaded {} flag(s) in one request:", snapshot.keys().len());
for key in snapshot.keys() {
println!(" - {key}");
}

if snapshot.is_enabled("new-dashboard") {
println!("\nnew-dashboard is enabled — render the new layout.");
}

if let Some(payload) = snapshot.get_flag_payload("onboarding-config") {
println!("\nonboarding-config payload (no event fired): {payload}");
}

// Capture an event that inherits the snapshot's flag context. No second
// /flags round-trip happens here.
let mut event = Event::new("checkout-started", user_id);
event.with_flags(&snapshot);
if let Err(e) = client.capture(event).await {
println!("capture failed: {e}");
}

// Optional: only attach the flags actually consulted on this request path.
let mut narrow = Event::new("checkout-completed", user_id);
narrow.with_flags(&snapshot.only_accessed());
let _ = client.capture(narrow).await;
}

#[cfg(not(feature = "async-client"))]
fn main() {
println!("This example requires the async-client feature.");
println!("Run with: cargo run --example evaluate_flags --features async-client");
}
Loading