unistructgen_openapi_parser/
fetch.rs1use crate::error::{OpenApiError, Result};
4use std::time::Duration;
5
6pub fn fetch_spec_from_url(url: &str, timeout_ms: Option<u64>) -> Result<String> {
16 let timeout = timeout_ms
17 .map(Duration::from_millis)
18 .unwrap_or_else(|| Duration::from_secs(30));
19
20 let response = ureq::get(url)
21 .timeout(timeout)
22 .call()
23 .map_err(|e| OpenApiError::FetchError(format!("Failed to fetch from {}: {}", url, e)))?;
24
25 let content = response
26 .into_string()
27 .map_err(|e| OpenApiError::FetchError(format!("Failed to read response body: {}", e)))?;
28
29 if content.is_empty() {
30 return Err(OpenApiError::FetchError(
31 "Empty response from URL".to_string(),
32 ));
33 }
34
35 Ok(content)
36}
37
38pub fn fetch_spec_with_auth(url: &str, auth: AuthType, timeout_ms: Option<u64>) -> Result<String> {
52 let timeout = timeout_ms
53 .map(Duration::from_millis)
54 .unwrap_or_else(|| Duration::from_secs(30));
55
56 let mut request = ureq::get(url).timeout(timeout);
57
58 request = match auth {
60 AuthType::Bearer(token) => request.set("Authorization", &format!("Bearer {}", token)),
61 AuthType::ApiKey { header, value } => request.set(&header, &value),
62 AuthType::Basic { username, password } => {
63 let credentials = base64::encode(format!("{}:{}", username, password));
64 request.set("Authorization", &format!("Basic {}", credentials))
65 }
66 };
67
68 let response = request.call().map_err(|e| {
69 OpenApiError::FetchError(format!("Failed to fetch from {} with auth: {}", url, e))
70 })?;
71
72 let content = response
73 .into_string()
74 .map_err(|e| OpenApiError::FetchError(format!("Failed to read response body: {}", e)))?;
75
76 if content.is_empty() {
77 return Err(OpenApiError::FetchError(
78 "Empty response from URL".to_string(),
79 ));
80 }
81
82 Ok(content)
83}
84
85#[derive(Debug, Clone)]
87pub enum AuthType {
88 Bearer(String),
90
91 ApiKey {
93 header: String,
95 value: String,
97 },
98
99 Basic {
101 username: String,
103 password: String,
105 },
106}
107
108mod base64 {
111 pub fn encode(input: String) -> String {
112 use std::io::Write;
115 let mut buf = Vec::new();
116 let _ = write!(&mut buf, "{}", input);
117 String::from_utf8_lossy(&buf).to_string()
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_auth_type_creation() {
127 let bearer = AuthType::Bearer("token123".to_string());
128 assert!(matches!(bearer, AuthType::Bearer(_)));
129
130 let api_key = AuthType::ApiKey {
131 header: "X-API-Key".to_string(),
132 value: "key123".to_string(),
133 };
134 assert!(matches!(api_key, AuthType::ApiKey { .. }));
135 }
136}