Official Elixir SDK for Togglr feature flag management system. This SDK provides a simple and efficient way to evaluate feature flags in your Elixir applications with built-in caching, retry logic, and error handling.
- Simple API: Easy-to-use interface for evaluating feature flags
- Context-aware: Support for user attributes, country, and custom properties
- Built-in Caching: LRU cache with TTL for improved performance
- Retry Logic: Configurable exponential backoff for failed requests
- Error Handling: Specific exceptions for different error scenarios
- Telemetry: Built-in telemetry events for monitoring and observability
- Type Safety: Comprehensive type specifications and documentation
Add togglr_sdk
to your list of dependencies in mix.exs
:
def deps do
[
{:togglr_sdk, "~> 1.0"}
]
end
Then run mix deps.get
to install the dependencies.
# Create a client
{:ok, client} = TogglrSdk.new_client("your-api-key")
# Create a context
context = TogglrSdk.RequestContext.new()
|> TogglrSdk.RequestContext.with_user_id("123")
|> TogglrSdk.RequestContext.with_country("US")
# Evaluate a feature
{:ok, result} = TogglrSdk.Client.evaluate(client, "new_ui", context)
IO.puts("Feature enabled: #{result.enabled}")
# Check if feature is enabled
{:ok, enabled} = TogglrSdk.Client.is_enabled(client, "new_ui", context)
IO.puts("Feature enabled: #{enabled}")
# Check with default value
{:ok, enabled} = TogglrSdk.Client.is_enabled_or_default(client, "new_ui", context, false)
IO.puts("Feature enabled: #{enabled}")
# Health check
{:ok, healthy} = TogglrSdk.Client.health_check(client)
IO.puts("API healthy: #{healthy}")
# Clean up
:ok = TogglrSdk.Client.close(client)
The SDK can be configured with various options:
# Using the convenience function
opts = [
base_url: "https://api.togglr.com",
timeout: 60000,
retries: 5,
cache_enabled: true,
cache_max_size: 2000,
cache_ttl: 120,
insecure: true # Skip SSL verification for self-signed certificates
]
{:ok, client} = TogglrSdk.new_client("your-api-key", opts)
# Or using the configuration module directly
config = TogglrSdk.Config.default("your-api-key")
|> TogglrSdk.Config.with_base_url("https://api.togglr.com")
|> TogglrSdk.Config.with_timeout(60000)
|> TogglrSdk.Config.with_retries(5)
|> TogglrSdk.Config.with_cache(true, 2000, 120)
|> TogglrSdk.Config.with_logger(MyLogger)
{:ok, client} = TogglrSdk.Client.new(config)
api_key
- Your Togglr API key (required)base_url
- API base URL (default: "http://localhost:8090")timeout
- Request timeout in milliseconds (default: 30000)retries
- Number of retries for failed requests (default: 3)cache_enabled
- Enable caching (default: true)cache_max_size
- Maximum number of entries in cache (default: 1000)cache_ttl
- Cache TTL in seconds (default: 60)logger
- Logger module (default: Logger)
The request context allows you to provide user attributes and other data for feature evaluation:
context = TogglrSdk.RequestContext.new()
|> TogglrSdk.RequestContext.with_user_id("123")
|> TogglrSdk.RequestContext.with_country("US")
|> TogglrSdk.RequestContext.set("plan", "premium")
|> TogglrSdk.RequestContext.set("region", "us-west")
|> TogglrSdk.RequestContext.set_many(%{
"user.role" => "admin",
"user.team" => "engineering"
})
# Evaluate a feature
{:ok, result} = TogglrSdk.Client.evaluate(client, "new_ui", context)
# result = %{value: "enabled", enabled: true, found: true}
# Check if feature is enabled
{:ok, enabled} = TogglrSdk.Client.is_enabled(client, "new_ui", context)
# enabled = true
# Check with default value
{:ok, enabled} = TogglrSdk.Client.is_enabled_or_default(client, "new_ui", context, false)
# enabled = true
The SDK supports reporting errors for features, which can trigger automatic disabling based on error rates:
# Report an error for a feature
:ok = TogglrSdk.Client.report_error(
client,
"feature_key",
"timeout",
"Service did not respond in 5s",
%{service: "payment-gateway", timeout_ms: 5000}
)
IO.puts("Error reported successfully - queued for processing")
Supported error types:
timeout
- Service timeoutvalidation
- Data validation errorservice_unavailable
- External service unavailablerate_limit
- Rate limit exceedednetwork
- Network connectivity issueinternal
- Internal application error
You can provide additional context with error reports:
context = %{
service: "payment-gateway",
timeout_ms: 5000,
user_id: "user123",
region: "us-east-1"
}
:ok = TogglrSdk.Client.report_error(
client,
"feature_key",
"timeout",
"Service timeout",
context
)
Monitor the health status of features:
# Get detailed health information
{:ok, health} = TogglrSdk.Client.get_feature_health(client, "feature_key")
IO.puts("Feature: #{health.feature_key}")
IO.puts("Enabled: #{health.enabled}")
IO.puts("Auto Disabled: #{health.auto_disabled}")
IO.puts("Error Rate: #{health.error_rate}")
IO.puts("Threshold: #{health.threshold}")
IO.puts("Last Error At: #{health.last_error_at}")
# Simple health check
{:ok, is_healthy} = TogglrSdk.Client.is_feature_healthy(client, "feature_key")
IO.puts("Feature is healthy: #{is_healthy}")
The TogglrSdk.Models.FeatureHealth
struct provides:
feature_key
- The feature identifierenvironment_key
- The environment identifierenabled
- Whether the feature is enabledauto_disabled
- Whether the feature was auto-disabled due to errorserror_rate
- Current error rate (0.0 to 1.0)threshold
- Error rate threshold for auto-disablelast_error_at
- Timestamp of the last errorhealthy?/1
- Function to check if feature is healthy
The TogglrSdk.Models.ErrorReport
struct provides:
error_type
- Type of errorerror_message
- Human-readable error messagecontext
- Additional context data
# Create an error report
error_report = TogglrSdk.Models.ErrorReport.new(
"timeout",
"Service timeout",
%{service: "api", timeout_ms: 5000}
)
# Convert to map for API requests
error_data = TogglrSdk.Models.ErrorReport.to_map(error_report)
The SDK provides specific exceptions for different error scenarios:
case TogglrSdk.Client.evaluate(client, "feature", context) do
{:ok, result} ->
# Handle success
process_result(result)
{:error, %TogglrSdk.Exceptions.FeatureNotFoundException{feature_key: feature_key}} ->
# Handle feature not found
IO.puts("Feature '#{feature_key}' not found")
{:error, %TogglrSdk.Exceptions.UnauthorizedException{}} ->
# Handle authentication error
IO.puts("Authentication failed")
{:error, %TogglrSdk.Exceptions.BadRequestException{}} ->
# Handle bad request
IO.puts("Invalid request")
{:error, reason} ->
# Handle other errors
IO.puts("Error: #{inspect(reason)}")
end
The SDK includes built-in LRU caching with TTL for improved performance:
# Enable caching with custom settings
config = TogglrSdk.Config.default("your-api-key")
|> TogglrSdk.Config.with_cache(true, 2000, 120) # enabled, max_size, ttl_seconds
{:ok, client} = TogglrSdk.Client.new(config)
Cache statistics are available through the cache module:
# Get cache statistics
stats = TogglrSdk.Cache.stats()
# stats = %{size: 150, hits: 1200, misses: 300}
Configure exponential backoff for retries:
# Create custom backoff configuration
backoff = TogglrSdk.BackoffConfig.new(0.5, 10.0, 1.5) # base_delay, max_delay, multiplier
config = TogglrSdk.Config.default("your-api-key")
|> TogglrSdk.Config.with_backoff(backoff)
|> TogglrSdk.Config.with_retries(5)
{:ok, client} = TogglrSdk.Client.new(config)
The SDK emits telemetry events for monitoring and observability:
defmodule MyTelemetry do
def handle_event([:togglr_sdk, :evaluate, :start], measurements, metadata, _config) do
# Handle evaluation start
IO.puts("Starting feature evaluation: #{metadata.feature_key}")
end
def handle_event([:togglr_sdk, :evaluate, :stop], measurements, metadata, _config) do
# Handle evaluation complete
IO.puts("Feature evaluation completed in #{measurements.duration}ms")
end
def handle_event([:togglr_sdk, :evaluate, :exception], measurements, metadata, _config) do
# Handle evaluation error
IO.puts("Feature evaluation failed: #{inspect(metadata.kind)}")
end
end
# Attach telemetry handler
:telemetry.attach("togglr-sdk", [:togglr_sdk, :evaluate], &MyTelemetry.handle_event/4, nil)
- Elixir 1.14 or later
- Mix 1.14 or later
- OpenAPI Generator CLI (for client generation)
# Clone the repository
git clone https://github.com/togglr/togglr-sdk-elixir.git
cd togglr-sdk-elixir
# Install dependencies
mix deps.get
# Run tests
mix test
# Run linting
mix credo --strict
mix dialyzer
# Format code
mix format
# Generate documentation
mix docs
This project automatically generates the API client from OpenAPI specifications. See DEVELOPMENT.md for detailed information about the generation process.
Quick commands:
# Generate API client
make generate
# Full regeneration (clean + generate)
make regenerate
# Apply modifications only
make post-generate
# Build the package
mix hex.build
# Publish to Hex (requires authentication)
mix hex.publish
See the examples/
directory for complete examples:
simple_example.exs
- Basic usage exampleadvanced_example.exs
- Advanced configuration and error handling
Run examples with:
elixir examples/simple_example.exs
elixir examples/advanced_example.exs
- Elixir 1.14+
- OTP 24+
- Tesla 1.4+
- Jason 1.4+
- Cachex 3.6+
- Telemetry 1.0+
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
For support, please open an issue on GitHub or contact the Togglr team.
See CHANGELOG.md for a list of changes and version history.