redis_cloud/lib.rs
1//! Redis Cloud REST API Client
2//!
3//! A comprehensive Rust client for the Redis Cloud REST API, providing full access to
4//! subscription management, database operations, billing, monitoring, and advanced features
5//! like VPC peering, SSO/SAML, and Private Service Connect.
6//!
7//! ## Features
8//!
9//! - **Subscription Management**: Create, update, delete subscriptions across AWS, GCP, Azure
10//! - **Database Operations**: Full CRUD operations, backups, imports, metrics
11//! - **Advanced Networking**: VPC peering, Transit Gateway, Private Service Connect
12//! - **Security & Access**: ACLs, SSO/SAML integration, API key management
13//! - **Monitoring & Billing**: Comprehensive metrics, logs, billing and payment management
14//! - **Enterprise Features**: Active-Active databases (CRDB), fixed/essentials plans
15//!
16//! ## Quick Start
17//!
18//! ```rust,no_run
19//! use redis_cloud::{CloudClient, DatabaseHandler};
20//!
21//! #[tokio::main]
22//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
23//! // Create client with API credentials
24//! let client = CloudClient::builder()
25//! .api_key("your-api-key")
26//! .api_secret("your-api-secret")
27//! .build()?;
28//!
29//! // List all databases
30//! let db_handler = DatabaseHandler::new(client.clone());
31//! let databases = db_handler.get_subscription_databases(123, None, None).await?;
32//! println!("Found databases: {:?}", databases);
33//!
34//! Ok(())
35//! }
36//! ```
37//!
38//! ## Core Usage Patterns
39//!
40//! ### Client Creation
41//!
42//! The client uses a builder pattern for flexible configuration:
43//!
44//! ```rust,no_run
45//! use redis_cloud::CloudClient;
46//!
47//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
48//! // Basic client with default settings
49//! let client = CloudClient::builder()
50//! .api_key("your-api-key")
51//! .api_secret("your-api-secret")
52//! .build()?;
53//!
54//! // Custom configuration
55//! let client2 = CloudClient::builder()
56//! .api_key("your-api-key")
57//! .api_secret("your-api-secret")
58//! .base_url("https://api.redislabs.com/v1".to_string())
59//! .timeout(std::time::Duration::from_secs(60))
60//! .build()?;
61//! # Ok(())
62//! # }
63//! ```
64//!
65//! ### Typed vs Raw API
66//!
67//! This client offers typed handlers for common operations as well as raw helpers when you
68//! need full control over request/response payloads:
69//!
70//! - Prefer typed handlers (e.g., `CloudDatabaseHandler`) for structured, ergonomic access.
71//! - Use raw helpers for passthroughs: `get_raw`, `post_raw`, `put_raw`, `patch_raw`, `delete_raw`.
72//!
73//! ```rust,no_run
74//! use redis_cloud::CloudClient;
75//! use serde_json::json;
76//!
77//! # #[tokio::main]
78//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
79//! let client = CloudClient::builder()
80//! .api_key("key")
81//! .api_secret("secret")
82//! .build()?;
83//!
84//! // Raw call example
85//! let created = client.post_raw("/subscriptions", json!({ "name": "example" })).await?;
86//! println!("{}", created);
87//! # Ok(())
88//! # }
89//! ```
90//!
91//! ### Working with Subscriptions
92//!
93//! ```rust,no_run
94//! use redis_cloud::{CloudClient, SubscriptionHandler};
95//! use serde_json::json;
96//!
97//! # #[tokio::main]
98//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
99//! let client = CloudClient::builder()
100//! .api_key("key")
101//! .api_secret("secret")
102//! .build()?;
103//!
104//! let sub_handler = SubscriptionHandler::new(client.clone());
105//!
106//! // List subscriptions
107//! let subscriptions = sub_handler.get_all_subscriptions().await?;
108//!
109//! // Create a new subscription using raw API
110//! let new_subscription = json!({
111//! "name": "my-redis-subscription",
112//! "provider": "AWS",
113//! "region": "us-east-1",
114//! "plan": "cache.m5.large"
115//! });
116//! let created = client.post_raw("/subscriptions", new_subscription).await?;
117//! # Ok(())
118//! # }
119//! ```
120//!
121//! ### Database Management
122//!
123//! ```rust,no_run
124//! use redis_cloud::{CloudClient, DatabaseHandler};
125//! use serde_json::json;
126//!
127//! # #[tokio::main]
128//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
129//! let client = CloudClient::builder()
130//! .api_key("key")
131//! .api_secret("secret")
132//! .build()?;
133//!
134//! let db_handler = DatabaseHandler::new(client.clone());
135//!
136//! // Create database using raw API
137//! let database_config = json!({
138//! "name": "my-database",
139//! "memoryLimitInGb": 1.0,
140//! "support_oss_cluster_api": false,
141//! "replication": true
142//! });
143//! let database = client.post_raw("/subscriptions/123/databases", database_config).await?;
144//!
145//! // Get database info
146//! let db_info = db_handler.get_subscription_database_by_id(123, 456).await?;
147//! # Ok(())
148//! # }
149//! ```
150//!
151//! ### Advanced Features
152//!
153//! #### VPC Peering
154//! ```rust,no_run
155//! use redis_cloud::{CloudClient, ConnectivityHandler};
156//! use serde_json::json;
157//!
158//! # #[tokio::main]
159//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
160//! let client = CloudClient::builder()
161//! .api_key("key")
162//! .api_secret("secret")
163//! .build()?;
164//!
165//! let peering_handler = ConnectivityHandler::new(client.clone());
166//!
167//! let peering_request = json!({
168//! "aws_account_id": "123456789012",
169//! "vpc_id": "vpc-12345678",
170//! "vpc_cidr": "10.0.0.0/16",
171//! "region": "us-east-1"
172//! });
173//! let peering = client.post_raw("/subscriptions/123/peerings", peering_request).await?;
174//! # Ok(())
175//! # }
176//! ```
177//!
178//! #### SSO/SAML Management
179//! ```rust,no_run
180//! use redis_cloud::{CloudClient, AccountHandler};
181//! use serde_json::json;
182//!
183//! # #[tokio::main]
184//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
185//! let client = CloudClient::builder()
186//! .api_key("key")
187//! .api_secret("secret")
188//! .build()?;
189//!
190//! let sso_handler = AccountHandler::new(client.clone());
191//!
192//! // Configure SSO using raw API
193//! let sso_config = json!({
194//! "enabled": true,
195//! "auto_provision": true
196//! });
197//! let config = client.put_raw("/sso", sso_config).await?;
198//! # Ok(())
199//! # }
200//! ```
201//!
202//! #### API Keys (Typed)
203//! ```rust,no_run
204//! use redis_cloud::{CloudClient, AccountHandler};
205//! use serde_json::json;
206//!
207//! # #[tokio::main]
208//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
209//! let client = CloudClient::builder()
210//! .api_key("key")
211//! .api_secret("secret")
212//! .build()?;
213//!
214//! let account = AccountHandler::new(client.clone());
215//! let account_info = account.get_current_account().await?;
216//! # Ok(())
217//! # }
218//! ```
219//!
220//! ## Error Handling
221//!
222//! The client provides comprehensive error handling for different failure scenarios:
223//!
224//! ```rust,no_run
225//! use redis_cloud::{CloudClient, CloudError, DatabaseHandler};
226//!
227//! # #[tokio::main]
228//! # async fn main() {
229//! let client = CloudClient::builder()
230//! .api_key("key")
231//! .api_secret("secret")
232//! .build().unwrap();
233//!
234//! let db_handler = DatabaseHandler::new(client.clone());
235//!
236//! match db_handler.get_subscription_database_by_id(123, 456).await {
237//! Ok(database) => println!("Database: {:?}", database),
238//! Err(CloudError::ApiError { code: 404, .. }) => {
239//! println!("Database not found");
240//! },
241//! Err(CloudError::AuthenticationFailed { message }) => {
242//! println!("Invalid API credentials");
243//! },
244//! Err(e) => println!("Other error: {}", e),
245//! }
246//! # }
247//! ```
248//!
249//! ## Handler Overview
250//!
251//! The client provides specialized handlers for different API domains:
252//!
253//! | Handler | Purpose | Key Operations |
254//! |---------|---------|----------------|
255//! | [`SubscriptionHandler`] | Pro subscriptions | create, list, update, delete, pricing |
256//! | [`FixedSubscriptionHandler`] | Essentials subscriptions | fixed plans, create, update, delete |
257//! | [`DatabaseHandler`] | Pro databases | create, backup, import, metrics, resize |
258//! | [`FixedDatabaseHandler`] | Essentials databases | fixed capacity, backup, import |
259//! | [`AccountHandler`] | Account management | info, API keys, payment methods, SSO |
260//! | [`UserHandler`] | User management | create, update, delete, invite, roles |
261//! | [`AclHandler`] | Access control | users, roles, Redis rules, database ACLs |
262//! | [`ConnectivityHandler`] | Network connectivity | VPC peering, Transit Gateway, PSC |
263//! | [`CloudAccountHandler`] | Cloud providers | AWS, GCP, Azure account integration |
264//! | [`TaskHandler`] | Async operations | track long-running operations |
265//!
266//! ## Authentication
267//!
268//! Redis Cloud uses API key authentication with two required headers:
269//! - `x-api-key`: Your API key
270//! - `x-api-secret-key`: Your API secret
271//!
272//! These credentials can be obtained from the Redis Cloud console under Account Settings > API Keys.
273//!
274//! Environment variables commonly used with this client:
275//! - `REDIS_CLOUD_API_KEY`
276//! - `REDIS_CLOUD_API_SECRET`
277//! - Optional: set a custom base URL via the builder for non‑prod/test environments (defaults to `https://api.redislabs.com/v1`).
278
279pub mod client;
280
281#[cfg(test)]
282mod lib_tests;
283
284// Re-export client types
285pub use client::{CloudClient, CloudClientBuilder};
286
287// Types module for shared models
288pub mod types;
289
290// Handler modules - each handles a specific API domain
291pub mod account;
292pub mod acl;
293pub mod cloud_accounts;
294pub mod connectivity;
295pub mod fixed;
296pub mod flexible;
297pub mod tasks;
298pub mod users;
299
300// Backward compatibility module aliases
301pub use fixed::databases as fixed_databases;
302pub use fixed::subscriptions as fixed_subscriptions;
303pub use flexible::databases;
304pub use flexible::subscriptions;
305
306// Re-export handlers with standard naming
307pub use account::AccountHandler;
308pub use acl::AclHandler;
309pub use cloud_accounts::CloudAccountsHandler as CloudAccountHandler;
310
311// Connectivity handlers
312pub use connectivity::psc::PscHandler;
313pub use connectivity::transit_gateway::TransitGatewayHandler;
314pub use connectivity::vpc_peering::VpcPeeringHandler;
315// Legacy connectivity export for backward compatibility
316pub use connectivity::ConnectivityHandler;
317
318// Fixed plan handlers
319pub use fixed::databases::FixedDatabaseHandler;
320pub use fixed::subscriptions::FixedSubscriptionHandler;
321// Legacy exports for backward compatibility
322pub use fixed::databases::FixedDatabaseHandler as FixedDatabasesHandler;
323pub use fixed::subscriptions::FixedSubscriptionHandler as FixedSubscriptionsHandler;
324
325// Flexible plan handlers (pay-as-you-go)
326pub use flexible::databases::DatabaseHandler;
327pub use flexible::subscriptions::SubscriptionHandler;
328// Legacy exports for backward compatibility
329pub use flexible::databases::DatabaseHandler as DatabasesHandler;
330pub use flexible::subscriptions::SubscriptionHandler as SubscriptionsHandler;
331
332pub use tasks::TasksHandler as TaskHandler;
333pub use users::UsersHandler as UserHandler;
334
335// Re-export error types
336use thiserror::Error;
337
338#[derive(Error, Debug)]
339pub enum CloudError {
340 #[error("HTTP request failed: {0}")]
341 Request(#[from] reqwest::Error),
342
343 #[error("Bad Request (400): {message}")]
344 BadRequest { message: String },
345
346 #[error("Authentication failed (401): {message}")]
347 AuthenticationFailed { message: String },
348
349 #[error("Forbidden (403): {message}")]
350 Forbidden { message: String },
351
352 #[error("Not Found (404): {message}")]
353 NotFound { message: String },
354
355 #[error("Precondition Failed (412): Feature flag for this flow is off")]
356 PreconditionFailed,
357
358 #[error("Internal Server Error (500): {message}")]
359 InternalServerError { message: String },
360
361 #[error("Service Unavailable (503): {message}")]
362 ServiceUnavailable { message: String },
363
364 #[error("API error ({code}): {message}")]
365 ApiError { code: u16, message: String },
366
367 #[error("Connection error: {0}")]
368 ConnectionError(String),
369
370 #[error("JSON error: {0}")]
371 JsonError(#[from] serde_json::Error),
372}
373
374pub type Result<T> = std::result::Result<T, CloudError>;