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