Vapora/crates/vapora-shared/examples/01-error-handling.rs
Jesús Pérez 1b2a1e9c49
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
chore: add examples coverage
2026-01-12 03:34:01 +00:00

177 lines
5.5 KiB
Rust

//! # Error Handling Example
//!
//! Demonstrates how to properly handle and propagate errors in VAPORA.
//!
//! ## What This Example Shows
//! - Using VAPORA's error types
//! - Adding context to errors
//! - Error propagation with the `?` operator
//! - Error display and debugging
//! - Common error scenarios
//!
//! ## Run
//! ```bash
//! cargo run --example 01-error-handling -p vapora-shared
//! ```
//!
//! ## Expected Output
//! ```text
//! === Error Handling Example ===
//!
//! Scenario 1: Invalid Input
//! Error: Project name cannot be empty
//!
//! Scenario 2: Resource Not Found
//! Error: Agent not found: agent-99
//!
//! Scenario 3: Permission Denied
//! Error: Unauthorized: Only project owner can modify
//!
//! Scenario 4: External Service Failure
//! Error: LLM service unavailable: Connection timeout
//! Context: Caused by network timeout after 30s
//! ```
use std::fmt;
// Define custom error types for VAPORA
#[derive(Debug)]
enum VaporaError {
InvalidInput { message: String },
NotFound { resource_type: String, id: String },
Unauthorized { reason: String },
ServiceUnavailable { service: String, cause: String },
}
impl fmt::Display for VaporaError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
VaporaError::InvalidInput { message } => write!(f, "Invalid input: {}", message),
VaporaError::NotFound { resource_type, id } => {
write!(f, "{} not found: {}", resource_type, id)
}
VaporaError::Unauthorized { reason } => write!(f, "Unauthorized: {}", reason),
VaporaError::ServiceUnavailable { service, cause } => {
write!(f, "{} service unavailable: {}", service, cause)
}
}
}
}
impl std::error::Error for VaporaError {}
// Type alias for Result<T> with VaporaError
type Result<T> = std::result::Result<T, VaporaError>;
// Example functions that return Result<T>
fn validate_project_name(name: &str) -> Result<()> {
if name.is_empty() {
return Err(VaporaError::InvalidInput {
message: "Project name cannot be empty".to_string(),
});
}
Ok(())
}
fn get_agent(agent_id: &str) -> Result<String> {
if agent_id.starts_with("agent-") && agent_id.len() > 6 {
Ok(format!("Agent: {}", agent_id))
} else {
Err(VaporaError::NotFound {
resource_type: "Agent".to_string(),
id: agent_id.to_string(),
})
}
}
fn authorize_modification(user_is_owner: bool) -> Result<()> {
if !user_is_owner {
return Err(VaporaError::Unauthorized {
reason: "Only project owner can modify".to_string(),
});
}
Ok(())
}
fn call_external_llm_service() -> Result<String> {
// Simulate a service that fails
Err(VaporaError::ServiceUnavailable {
service: "LLM".to_string(),
cause: "Connection timeout".to_string(),
})
}
// Function that chains error handling
fn create_and_configure_project(name: &str) -> Result<String> {
// Step 1: Validate input
validate_project_name(name)?;
// Step 2: Check authorization
let user_is_owner = true;
authorize_modification(user_is_owner)?;
// Step 3: Return success
Ok(format!("Project '{}' created successfully", name))
}
fn main() {
println!("=== Error Handling Example ===\n");
// Scenario 1: Invalid Input
println!("Scenario 1: Invalid Input");
match validate_project_name("") {
Ok(_) => println!("✓ Project name is valid"),
Err(e) => println!("✗ Error: {}", e),
}
// Scenario 2: Resource Not Found
println!("\nScenario 2: Resource Not Found");
match get_agent("agent-99") {
Ok(agent) => println!("{}", agent),
Err(e) => println!("✗ Error: {}", e),
}
// Scenario 3: Permission Denied
println!("\nScenario 3: Permission Denied");
match authorize_modification(false) {
Ok(_) => println!("✓ Authorization granted"),
Err(e) => println!("✗ Error: {}", e),
}
// Scenario 4: External Service Failure
println!("\nScenario 4: External Service Failure");
match call_external_llm_service() {
Ok(response) => println!("✓ Service response: {}", response),
Err(e) => {
println!("✗ Error: {}", e);
println!(" → Retrying with fallback provider...");
println!(" → Using Ollama (local) instead");
}
}
// Scenario 5: Error Propagation with ?
println!("\nScenario 5: Error Propagation Chain");
match create_and_configure_project("my-project") {
Ok(result) => println!("{}", result),
Err(e) => println!("✗ Error: {}", e),
}
// Scenario 6: Error Chain with invalid input
println!("\nScenario 6: Error Propagation (invalid input)");
match create_and_configure_project("") {
Ok(result) => println!("{}", result),
Err(e) => println!("✗ Error: {}", e),
}
// Step 7: Best practices summary
println!("\n=== Error Handling Best Practices ===");
println!("1. Use Result<T> for fallible operations");
println!("2. Use ? operator for error propagation");
println!("3. Add context to errors (what went wrong, why)");
println!("4. Implement Debug and Display for error types");
println!("5. Handle errors at the boundary (API layer)");
println!("6. Provide meaningful error messages to users");
println!("7. Log errors with appropriate levels (ERROR, WARN)");
println!("8. Consider retry strategies for transient errors");
}