Skip to main content

alien_manager_api/
lib.rs

1//! Alien Manager API
2//!
3//! Auto-generated from OpenAPI spec using Progenitor.
4//! Provides a type-safe Rust client for the alien-manager API.
5//!
6//! ## Usage
7//!
8//! ```ignore
9//! use alien_manager_api::Client;
10//!
11//! let client = Client::new("http://localhost:8080");
12//!
13//! // Create a deployment
14//! let response = client
15//!     .create_deployment()
16//!     .body(&CreateDeploymentRequest {
17//!         name: "my-deployment".into(),
18//!         platform: Platform::Aws,
19//!         ..Default::default()
20//!     })
21//!     .send()
22//!     .await?;
23//! ```
24
25include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
26
27use alien_error::{AlienError, GenericError, HumanLayerPresentation};
28
29/// Extension trait for converting manager SDK results to `AlienError`.
30pub trait SdkResultExt<T> {
31    /// Convert SDK result to `AlienError` result, preserving API error details.
32    fn into_sdk_error(self) -> Result<T, AlienError<GenericError>>;
33}
34
35impl<T> SdkResultExt<ResponseValue<T>> for Result<ResponseValue<T>, Error<()>> {
36    fn into_sdk_error(self) -> Result<ResponseValue<T>, AlienError<GenericError>> {
37        self.map_err(convert_sdk_error)
38    }
39}
40
41/// Convert a progenitor SDK error to AlienError, preserving all details.
42pub fn convert_sdk_error(err: Error<()>) -> AlienError<GenericError> {
43    match err {
44        Error::ErrorResponse(response) => {
45            let status = response.status().as_u16();
46            AlienError {
47                code: "UNEXPECTED_RESPONSE".to_string(),
48                message: format!(
49                    "Unexpected response: {} {}",
50                    status,
51                    response.status().canonical_reason().unwrap_or("Unknown")
52                ),
53                context: Some(serde_json::json!({
54                    "status": status,
55                })),
56                hint: None,
57                retryable: status >= 500,
58                internal: false,
59                http_status_code: Some(status),
60                source: None,
61                human_layer_presentation: HumanLayerPresentation::Normal,
62                error: Some(GenericError {
63                    message: format!("Unexpected response status: {}", status),
64                }),
65            }
66        }
67        Error::CommunicationError(reqwest_err) => {
68            let retryable =
69                reqwest_err.is_connect() || reqwest_err.is_timeout() || reqwest_err.is_request();
70
71            AlienError {
72                code: "COMMUNICATION_ERROR".to_string(),
73                message: format!("Communication Error: {}", reqwest_err),
74                context: None,
75                hint: None,
76                retryable,
77                internal: false,
78                http_status_code: reqwest_err.status().map(|s| s.as_u16()),
79                source: build_reqwest_source(&reqwest_err),
80                human_layer_presentation: HumanLayerPresentation::Normal,
81                error: Some(GenericError {
82                    message: format!("Communication Error: {}", reqwest_err),
83                }),
84            }
85        }
86        Error::InvalidRequest(msg) => AlienError {
87            code: "INVALID_REQUEST".to_string(),
88            message: format!("Invalid Request: {}", msg),
89            context: None,
90            hint: None,
91            retryable: false,
92            internal: false,
93            http_status_code: Some(400),
94            source: None,
95            human_layer_presentation: HumanLayerPresentation::Normal,
96            error: Some(GenericError {
97                message: format!("Invalid Request: {}", msg),
98            }),
99        },
100        Error::ResponseBodyError(reqwest_err) => AlienError {
101            code: "RESPONSE_BODY_ERROR".to_string(),
102            message: format!("Error reading response body: {}", reqwest_err),
103            context: None,
104            hint: None,
105            retryable: true,
106            internal: false,
107            http_status_code: reqwest_err.status().map(|s| s.as_u16()),
108            source: build_reqwest_source(&reqwest_err),
109            human_layer_presentation: HumanLayerPresentation::Normal,
110            error: Some(GenericError {
111                message: format!("Error reading response body: {}", reqwest_err),
112            }),
113        },
114        Error::InvalidResponsePayload(bytes, json_err) => {
115            let raw_body = String::from_utf8_lossy(&bytes);
116            let truncated = if raw_body.len() > 1000 {
117                format!(
118                    "{}...(truncated {} bytes)",
119                    &raw_body[..1000],
120                    raw_body.len() - 1000
121                )
122            } else {
123                raw_body.to_string()
124            };
125
126            AlienError {
127                code: "INVALID_RESPONSE_PAYLOAD".to_string(),
128                message: format!("Failed to parse response: {}", json_err),
129                context: Some(serde_json::json!({
130                    "parseError": json_err.to_string(),
131                    "responseBody": truncated,
132                })),
133                hint: None,
134                retryable: false,
135                internal: false,
136                http_status_code: None,
137                source: Some(Box::new(AlienError::new(GenericError {
138                    message: json_err.to_string(),
139                }))),
140                human_layer_presentation: HumanLayerPresentation::Normal,
141                error: Some(GenericError {
142                    message: format!("Failed to parse response: {}", json_err),
143                }),
144            }
145        }
146        Error::InvalidUpgrade(reqwest_err) => AlienError {
147            code: "INVALID_UPGRADE".to_string(),
148            message: format!("Connection upgrade failed: {}", reqwest_err),
149            context: None,
150            hint: None,
151            retryable: false,
152            internal: false,
153            http_status_code: reqwest_err.status().map(|s| s.as_u16()),
154            source: build_reqwest_source(&reqwest_err),
155            human_layer_presentation: HumanLayerPresentation::Normal,
156            error: Some(GenericError {
157                message: format!("Connection upgrade failed: {}", reqwest_err),
158            }),
159        },
160        Error::UnexpectedResponse(response) => {
161            let status = response.status().as_u16();
162            AlienError {
163                code: "UNEXPECTED_RESPONSE".to_string(),
164                message: format!(
165                    "Unexpected response: {} {}",
166                    status,
167                    response.status().canonical_reason().unwrap_or("Unknown")
168                ),
169                context: Some(serde_json::json!({
170                    "status": status,
171                    "url": response.url().to_string(),
172                })),
173                hint: None,
174                retryable: status >= 500,
175                internal: false,
176                http_status_code: Some(status),
177                source: None,
178                human_layer_presentation: HumanLayerPresentation::Normal,
179                error: Some(GenericError {
180                    message: format!("Unexpected response status: {}", status),
181                }),
182            }
183        }
184        Error::Custom(msg) => AlienError {
185            code: "SDK_HOOK_ERROR".to_string(),
186            message: msg.clone(),
187            context: None,
188            hint: None,
189            retryable: false,
190            internal: false,
191            http_status_code: None,
192            source: None,
193            human_layer_presentation: HumanLayerPresentation::Normal,
194            error: Some(GenericError { message: msg }),
195        },
196    }
197}
198
199fn build_reqwest_source(reqwest_err: &reqwest::Error) -> Option<Box<AlienError<GenericError>>> {
200    use std::error::Error as _;
201
202    reqwest_err.source().map(|source| {
203        Box::new(AlienError {
204            code: "GENERIC_ERROR".to_string(),
205            message: source.to_string(),
206            context: None,
207            hint: None,
208            retryable: false,
209            internal: false,
210            http_status_code: None,
211            source: None,
212            human_layer_presentation: HumanLayerPresentation::Transparent,
213            error: Some(GenericError {
214                message: source.to_string(),
215            }),
216        })
217    })
218}