base_error_handling/
base_error_handling.rs

1//! # Error Handling Patterns
2//!
3//! This example demonstrates how to work with Alpaca error types,
4//! including error codes, retryable errors, and validation errors.
5//!
6//! ## Usage
7//!
8//! ```bash
9//! cargo run --example base_error_handling
10//! ```
11//!
12//! ## Expected Output
13//!
14//! Demonstrates various error types and their properties.
15
16use alpaca_base::{AlpacaError, ApiErrorCode, ApiErrorResponse, RateLimitInfo, ValidationError};
17
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19    println!("=== Alpaca Error Handling Patterns ===\n");
20
21    // 1. API Error Codes
22    println!("--- API Error Codes ---");
23    demonstrate_error_codes();
24
25    // 2. Retryable Errors
26    println!("\n--- Retryable Errors ---");
27    demonstrate_retryable_errors();
28
29    // 3. Rate Limiting
30    println!("\n--- Rate Limit Handling ---");
31    demonstrate_rate_limiting();
32
33    // 4. Validation Errors
34    println!("\n--- Validation Errors ---");
35    demonstrate_validation_errors();
36
37    // 5. Error Matching
38    println!("\n--- Error Pattern Matching ---");
39    demonstrate_error_matching();
40
41    println!("\n=== Example Complete ===");
42    Ok(())
43}
44
45fn demonstrate_error_codes() {
46    // Convert numeric codes to typed error codes
47    let codes = [
48        (40010000, "Malformed Request"),
49        (40110000, "Invalid Credentials"),
50        (40310000, "Forbidden"),
51        (40410000, "Not Found"),
52        (42210000, "Unprocessable Entity"),
53        (42910000, "Rate Limit Exceeded"),
54        (50010000, "Internal Server Error"),
55    ];
56
57    for (code, description) in codes {
58        let error_code = ApiErrorCode::from_code(code);
59        println!(
60            "  Code {}: {} (client_error={}, server_error={})",
61            code,
62            description,
63            error_code.is_client_error(),
64            error_code.is_server_error()
65        );
66    }
67}
68
69fn demonstrate_retryable_errors() {
70    let errors = [
71        ("Rate Limit", AlpacaError::rate_limit(60)),
72        (
73            "Network",
74            AlpacaError::Network("connection reset".to_string()),
75        ),
76        (
77            "Timeout",
78            AlpacaError::Timeout("request timed out".to_string()),
79        ),
80        ("Auth", AlpacaError::Auth("invalid key".to_string())),
81        ("Not Found", AlpacaError::api(404, "order not found")),
82        ("Server Error", AlpacaError::api(500, "internal error")),
83    ];
84
85    for (name, error) in errors {
86        let retry_info = if let Some(secs) = error.retry_after() {
87            format!(", retry after {} secs", secs)
88        } else {
89            String::new()
90        };
91        println!(
92            "  {}: retryable={}{}",
93            name,
94            error.is_retryable(),
95            retry_info
96        );
97    }
98}
99
100fn demonstrate_rate_limiting() {
101    // Create rate limit info from API response headers
102    let info = RateLimitInfo::new()
103        .with_remaining(0)
104        .with_limit(200)
105        .with_retry_after(60);
106
107    println!("  Rate limit status:");
108    println!("    - Remaining: {:?}", info.remaining);
109    println!("    - Limit: {:?}", info.limit);
110    println!("    - Retry after: {:?} seconds", info.retry_after);
111    println!("    - Is limited: {}", info.is_limited());
112
113    // Create error with full rate limit info
114    let error = AlpacaError::rate_limit_with_info(info);
115    println!("  Error: {}", error);
116}
117
118fn demonstrate_validation_errors() {
119    // Single validation error
120    let single_error = ValidationError::new("quantity", "must be greater than 0");
121    println!("  Single error: {}", single_error);
122
123    // Multiple validation errors
124    let errors = vec![
125        ValidationError::new("symbol", "is required"),
126        ValidationError::new("qty", "must be positive"),
127        ValidationError::new("side", "must be 'buy' or 'sell'"),
128    ];
129
130    let multi_error = AlpacaError::ValidationErrors(errors);
131    println!("  Multiple errors: {}", multi_error);
132}
133
134fn demonstrate_error_matching() {
135    let error = AlpacaError::api_with_details(
136        404,
137        "order not found",
138        ApiErrorCode::NotFound,
139        Some("req-12345".to_string()),
140    );
141
142    // Pattern match on error type
143    match &error {
144        AlpacaError::Api {
145            status,
146            message,
147            error_code,
148            request_id,
149        } => {
150            println!("  API Error detected:");
151            println!("    - Status: {}", status);
152            println!("    - Message: {}", message);
153            println!("    - Error code: {:?}", error_code);
154            println!("    - Request ID: {:?}", request_id);
155        }
156        AlpacaError::RateLimit {
157            retry_after_secs, ..
158        } => {
159            println!("  Rate limited, retry after {} seconds", retry_after_secs);
160        }
161        _ => {
162            println!("  Other error: {}", error);
163        }
164    }
165
166    // Use helper methods
167    println!("\n  Helper methods:");
168    println!("    - status_code(): {:?}", error.status_code());
169    println!("    - request_id(): {:?}", error.request_id());
170    println!("    - is_retryable(): {}", error.is_retryable());
171
172    // API error response parsing
173    let response =
174        ApiErrorResponse::new(40410000, "resource not found").with_request_id("req-67890");
175    println!("\n  Parsed API response:");
176    println!("    - Code: {}", response.code);
177    println!("    - Message: {}", response.message);
178    println!("    - Typed code: {:?}", response.error_code());
179}