Architecture
redisctl is built as a collection of reusable Rust libraries with a thin CLI layer on top.
Workspace Structure
redisctl/
├── crates/
│ ├── redisctl-config/ # Profile and credential management
│ ├── redis-cloud/ # Cloud API client library
│ ├── redis-enterprise/ # Enterprise API client library
│ └── redisctl/ # CLI application
└── docs/ # mdBook documentation
Library Layers
redisctl-config
Profile and credential management:
- Configuration file parsing
- Secure credential storage (OS keyring)
- Environment variable handling
#![allow(unused)]
fn main() {
use redisctl_config::{Config, Profile};
let config = Config::load()?;
let profile = config.get_profile("production")?;
}
redis-cloud
Redis Cloud API client:
- 21 handler modules
- 95%+ API coverage
- Async/await support
#![allow(unused)]
fn main() {
use redis_cloud::CloudClient;
let client = CloudClient::new(api_key, api_secret)?;
let subscriptions = client.subscriptions().list().await?;
}
redis-enterprise
Redis Enterprise API client:
- 29 handler modules
- 100% API coverage
- Support for binary responses (debug info, support packages)
#![allow(unused)]
fn main() {
use redis_enterprise::EnterpriseClient;
let client = EnterpriseClient::new(url, username, password)?;
let cluster = client.cluster().get().await?;
}
redisctl
CLI application:
- Command parsing (clap)
- Output formatting
- Workflow orchestration
Design Principles
Library-First
The API clients are independent libraries that can be used by other tools (Terraform providers, monitoring dashboards, etc.).
Type-Safe
All API responses are deserialized into Rust structs, catching errors at compile time.
Handler Pattern
Each API resource has a handler module with methods for CRUD operations:
#![allow(unused)]
fn main() {
// Handler pattern
client.databases().list().await?;
client.databases().get(id).await?;
client.databases().create(config).await?;
}
Async Operations
Built on Tokio for async I/O. Long-running operations return task IDs with optional polling.
Error Handling
- Libraries: Use
thiserrorfor typed errors - CLI: Use
anyhowfor context-rich messages
#![allow(unused)]
fn main() {
// Library error
#[derive(Error, Debug)]
pub enum CloudError {
#[error("API request failed: {0}")]
Request(#[from] reqwest::Error),
#[error("Authentication failed")]
Auth,
}
// CLI error handling
let result = client.databases().get(id).await
.context("Failed to fetch database")?;
}
Output System
Three-tier output formatting:
- JSON (default) - Machine-readable
- YAML - Human-readable structured
- Table - Human-readable tabular
JMESPath queries filter output before formatting.
Future Libraries
Planned extractions:
redisctl-workflows- Reusable workflow orchestrationredisctl-output- Consistent output formatting