# ABsmartly SDK for Rust
[](https://crates.io/crates/absmartly-sdk)
[](https://docs.rs/absmartly-sdk)
[](https://opensource.org/licenses/MIT)
A Rust SDK for [ABsmartly](https://www.absmartly.com) - A/B testing and feature flagging platform.
## Compatibility
The ABsmartly Rust SDK is compatible with Rust 2021 edition and later. It provides a synchronous interface for variant assignment and goal tracking.
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
absmartly-sdk = "0.1"
```
## Getting Started
Please follow the [installation](#installation) instructions before trying the following code.
### Initialization
This example assumes an API Key, an Application, and an Environment have been created in the ABsmartly web console.
```rust
use absmartly_sdk::{SDK, SDKOptions};
let sdk = SDK::new(SDKOptions::default());
```
### Creating a New Context with Pre-fetched Data
When doing full-stack experimentation with ABsmartly, we recommend creating a context only once on the server-side. Creating a context involves a round-trip to the ABsmartly event collector. We can avoid repeating the round-trip on the client-side by sending the server-side data embedded in the first document.
```rust
use absmartly_sdk::{SDK, SDKOptions, ContextData};
let sdk = SDK::new(SDKOptions::default());
// Define units for the context - accepts arrays of tuples (no .to_string() needed!)
let units = [("session_id", "5ebf06d8cb5d8137290c4abb64155584fbdb64d8")];
// Load context data from ABsmartly API (you'll need to fetch this from your backend)
let context_data: ContextData = serde_json::from_str(&api_response).unwrap();
// Create context with pre-fetched data
let mut context = sdk.create_context_with(units, context_data, None);
```
### Setting Extra Units for a Context
You can add additional units to a context by calling the `set_unit()` method. This method may be used, for example, when a user logs in to your application, and you want to use the new unit type in the context.
**Note:** You cannot override an already set unit type as that would be a change of identity. In this case, you must create a new context instead.
```rust
context.set_unit("db_user_id", "1000013").unwrap();
```
### Setting Context Attributes
Attributes are used for audience targeting. The `set_attribute()` method can be called before the context is ready. It accepts native Rust types directly:
```rust
// Accepts native Rust types - no json!() macro needed!
context.set_attribute("user_agent", "Mozilla/5.0").unwrap();
context.set_attribute("customer_age", "new_customer").unwrap();
context.set_attribute("age", 25).unwrap();
context.set_attribute("premium", true).unwrap();
```
### Selecting a Treatment
```rust
let variant = context.treatment("exp_test_experiment");
if variant == 0 {
// User is in control group (variant 0)
println!("Control group");
} else {
// User is in treatment group
println!("Treatment group: variant {}", variant);
}
```
### Tracking a Goal Achievement
Goals are created in the ABsmartly web console.
```rust
use serde_json::json;
// Track a simple goal (use () for no properties)
context.track("payment", ()).unwrap();
// Track a goal with properties using json!()
context.track("purchase", json!({
"item_count": 1,
"total_amount": 1999.99
})).unwrap();
```
### Publishing Pending Data
Sometimes it is necessary to ensure all events have been published to the ABsmartly collector before proceeding. You can explicitly call the `publish()` method.
```rust
let publish_params = context.publish();
// Send publish_params to ABsmartly collector API
```
### Finalizing
The `finalize()` method will ensure all events have been published to the ABsmartly collector, like `publish()`, and will also "seal" the context, preventing any further events from being tracked.
```rust
context.finalize();
// Context is now sealed - no more treatments or goals can be tracked
```
## Basic Usage
### Peek at Treatment Variants
Although generally not recommended, it is sometimes necessary to peek at a treatment without triggering an exposure. The ABsmartly SDK provides a `peek()` method for that.
```rust
let variant = context.peek("exp_test_experiment");
if variant == 0 {
// User is in control group (variant 0)
} else {
// User is in treatment group
}
```
### Overriding Treatment Variants
During development, for example, it is useful to force a treatment for an experiment. This can be achieved with the `set_override()` method.
```rust
context.set_override("exp_test_experiment", 1); // Force variant 1
// You can also set multiple overrides
context.set_override("exp_another_experiment", 0);
```
### Custom Assignments
Custom assignments allow you to set a specific variant for an experiment programmatically.
```rust
context.set_custom_assignment("exp_test_experiment", 1).unwrap();
```
## Variable Values
Get configuration values from experiments. Variables allow you to configure different values for each variant.
```rust
// Get a variable value with a default fallback
// Accepts native Rust types - no json!() macro needed!
let button_color = context.variable_value("button.color", "blue");
println!("Button color: {}", button_color);
// Get other types of variables
let show_banner = context.variable_value("banner.show", false);
let max_items = context.variable_value("cart.max_items", 10);
```
## Advanced Usage
### Getting Experiment Data
You can retrieve information about experiments in the current context.
```rust
// Get all experiment names
let experiments = context.get_experiments();
for name in experiments {
println!("Experiment: {}", name);
}
// Get custom field value for an experiment
if let Some(value) = context.get_custom_field_value("exp_test", "analyst") {
println!("Analyst: {}", value);
}
```
### Checking Variable Keys
You can get all variable keys for an experiment.
```rust
let keys = context.variable_keys();
for key in keys {
println!("Variable key: {}", key);
}
```
## Context Data Structure
The SDK expects context data in the following format (typically fetched from the ABsmartly API):
```rust
use absmartly_sdk::ContextData;
let context_data = ContextData {
experiments: vec![
// Experiment configurations from ABsmartly API
],
};
```
## Error Handling
The SDK uses Rust's `Result` type for error handling:
```rust
use absmartly_sdk::SDKError;
match context.set_unit("user_id", "12345") {
Ok(_) => println!("Unit set successfully"),
Err(SDKError::UnitAlreadySet(unit_type)) => {
println!("Cannot override unit type: {}", unit_type);
}
Err(e) => println!("Error: {:?}", e),
}
```
## Thread Safety
The Context is designed for single-threaded use. If you need to use it across threads, wrap it in appropriate synchronization primitives like `Arc<Mutex<Context>>`.
## Documentation
- [API Documentation](https://docs.rs/absmartly-sdk)
- [ABsmartly Documentation](https://docs.absmartly.com)
## About ABsmartly
**ABsmartly** is the leading provider of state-of-the-art, on-premises, full-stack experimentation platforms for engineering and product teams that want to confidently deploy features as fast as they can develop them.
ABsmartly's real-time analytics helps engineering and product teams ensure that new features will improve the customer experience without breaking or degrading performance and/or business metrics.
### Have a look at our growing list of SDKs:
- [Java SDK](https://www.github.com/absmartly/java-sdk)
- [JavaScript SDK](https://www.github.com/absmartly/javascript-sdk)
- [PHP SDK](https://www.github.com/absmartly/php-sdk)
- [Swift SDK](https://www.github.com/absmartly/swift-sdk)
- [Vue2 SDK](https://www.github.com/absmartly/vue2-sdk)
- [Vue3 SDK](https://www.github.com/absmartly/vue3-sdk)
- [React SDK](https://www.github.com/absmartly/react-sdk)
- [Ruby SDK](https://www.github.com/absmartly/ruby-sdk)
- [Golang SDK](https://www.github.com/absmartly/go-sdk)
- [Flutter/Dart SDK](https://www.github.com/absmartly/flutter-sdk)
- [Python3 SDK](https://www.github.com/absmartly/python3-sdk)
- [.NET SDK](https://www.github.com/absmartly/dotnet-sdk)
- [Rust SDK](https://www.github.com/absmartly/rust-sdk)
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.