use crate::error::{OpenApiError, Result};
use std::time::Duration;
pub fn fetch_spec_from_url(url: &str, timeout_ms: Option<u64>) -> Result<String> {
let timeout = timeout_ms
.map(Duration::from_millis)
.unwrap_or_else(|| Duration::from_secs(30));
let response = ureq::get(url)
.timeout(timeout)
.call()
.map_err(|e| OpenApiError::FetchError(format!("Failed to fetch from {}: {}", url, e)))?;
let content = response
.into_string()
.map_err(|e| OpenApiError::FetchError(format!("Failed to read response body: {}", e)))?;
if content.is_empty() {
return Err(OpenApiError::FetchError(
"Empty response from URL".to_string(),
));
}
Ok(content)
}
pub fn fetch_spec_with_auth(url: &str, auth: AuthType, timeout_ms: Option<u64>) -> Result<String> {
let timeout = timeout_ms
.map(Duration::from_millis)
.unwrap_or_else(|| Duration::from_secs(30));
let mut request = ureq::get(url).timeout(timeout);
request = match auth {
AuthType::Bearer(token) => request.set("Authorization", &format!("Bearer {}", token)),
AuthType::ApiKey { header, value } => request.set(&header, &value),
AuthType::Basic { username, password } => {
let credentials = base64::encode(format!("{}:{}", username, password));
request.set("Authorization", &format!("Basic {}", credentials))
}
};
let response = request.call().map_err(|e| {
OpenApiError::FetchError(format!("Failed to fetch from {} with auth: {}", url, e))
})?;
let content = response
.into_string()
.map_err(|e| OpenApiError::FetchError(format!("Failed to read response body: {}", e)))?;
if content.is_empty() {
return Err(OpenApiError::FetchError(
"Empty response from URL".to_string(),
));
}
Ok(content)
}
#[derive(Debug, Clone)]
pub enum AuthType {
Bearer(String),
ApiKey {
header: String,
value: String,
},
Basic {
username: String,
password: String,
},
}
mod base64 {
pub fn encode(input: String) -> String {
use std::io::Write;
let mut buf = Vec::new();
let _ = write!(&mut buf, "{}", input);
String::from_utf8_lossy(&buf).to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_auth_type_creation() {
let bearer = AuthType::Bearer("token123".to_string());
assert!(matches!(bearer, AuthType::Bearer(_)));
let api_key = AuthType::ApiKey {
header: "X-API-Key".to_string(),
value: "key123".to_string(),
};
assert!(matches!(api_key, AuthType::ApiKey { .. }));
}
}