# flagbearer for Rust

The Rust SDK for Flagbearer. Requires Rust 1.85 or later.

## Install

```sh
cargo add flagbearer
```

## Keys

Use a server key, which starts with `fbs_`. Server keys are secret: read them
from the environment, such as `FLAGBEARER_SERVER_KEY`, and never put them in
browser code or in the repository. Browsers use client keys, which start with
`fbc_`, through [`@flagbearer/web`](/sdks/web).

## Sync at startup

Create one client per process, when the app starts, and wait for it to sync
before accepting requests:

```rust
use std::time::Duration;

let flags = flagbearer::Client::new(
    std::env::var("FLAGBEARER_SERVER_KEY")?,
    flagbearer::Options::default(),
)?;

if let Err(error) = flags.sync_timeout(Duration::from_secs(10)) {
    // Keep starting: checks use their defaults, and the SDK retries in the background.
    eprintln!("Initial Flagbearer sync failed: {error}");
}
```

## Check per request

Share the client across requests, for example in an `Arc`, and pass each
request's user explicitly with a default. This axum app syncs once at startup:

```rust
use std::sync::Arc;

use axum::{extract::State, routing::get, Router};
use flagbearer::{Client, Options, User};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let flags = Arc::new(Client::new(
        std::env::var("FLAGBEARER_SERVER_KEY")?,
        Options::default(),
    )?);

    let startup = Arc::clone(&flags);
    if let Err(error) = tokio::task::spawn_blocking(move || startup.sync()).await? {
        eprintln!("Initial Flagbearer sync failed: {error}");
    }

    let app = Router::new()
        .route("/search", get(search))
        .with_state(flags);
    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(listener, app).await?;
    Ok(())
}

async fn search(State(flags): State<Arc<Client>>) -> &'static str {
    let user = User {
        key: Some("user-1".into()),
        email: Some("ann@example.com".into()),
    };
    if flags.is_enabled("advanced-search", &user, false) {
        "advanced"
    } else {
        "basic"
    }
}
```

The email is optional. Include it to turn flags on for testers by email.
The default is used until the client has synced, and when the flag doesn't
exist.

## Shut down

Keep the client for the life of the process, not per request. Close it on
shutdown:

```rust
if let Err(error) = flags.close() {
    eprintln!("Final Flagbearer upload failed: {error}");
}
```

In async code, close it on a blocking thread. Serverless functions should call
`flags.flush()` at the end of each invocation.
