HttpClient

Trait HttpClient 

Source
pub trait HttpClient: Send + Sync {
    // Required methods
    fn request<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        method: Method,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: Option<&'life2 T>,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;
    fn request_with_retry<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        method: Method,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: Option<&'life2 T>,
        _max_retries: u32,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + Clone + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait;

    // Provided methods
    fn get<'life0, 'life1, 'async_trait, R>(
        &'life0 self,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn post<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: &'life2 T,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn put<'life0, 'life1, 'life2, 'async_trait, T, R>(
        &'life0 self,
        url: &'life1 str,
        headers: Option<HashMap<String, String>>,
        body: &'life2 T,
    ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
       where T: Serialize + Send + Sync + 'async_trait,
             R: for<'de> Deserialize<'de> + 'async_trait,
             Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
}
Expand description

HTTP transport client abstraction, defining common HTTP operation interface

HTTP transport client abstraction defining generic HTTP operation interface

This trait defines the generic interface for all HTTP operations, allowing the adapter layer to avoid direct interaction with reqwest

Required Methodsยง

Source

fn request<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, method: Method, url: &'life1 str, headers: Option<HashMap<String, String>>, body: Option<&'life2 T>, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send HTTP request

Source

fn request_with_retry<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, method: Method, url: &'life1 str, headers: Option<HashMap<String, String>>, body: Option<&'life2 T>, _max_retries: u32, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + Clone + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send HTTP request with retry

Provided Methodsยง

Source

fn get<'life0, 'life1, 'async_trait, R>( &'life0 self, url: &'life1 str, headers: Option<HashMap<String, String>>, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Send GET request

Examples found in repository?
examples/debug_openai_transport.rs (line 28)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("๐Ÿ” OpenAI Transport Layer Debugging");
9    println!("==================================");
10
11    let api_key = match std::env::var("OPENAI_API_KEY") {
12        Ok(key) => key,
13        Err(_) => {
14            println!("โŒ OPENAI_API_KEY not set");
15            return Ok(());
16        }
17    };
18
19    // Use our HttpTransport
20    let transport = HttpTransport::new();
21
22    // Test GET request (model list) - we know this works
23    println!("\n๐Ÿ“‹ Test GET request (model list):");
24    let mut headers = HashMap::new();
25    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
26
27    match transport
28        .get::<serde_json::Value>("https://api.openai.com/v1/models", Some(headers))
29        .await
30    {
31        Ok(response) => {
32            let model_count = response["data"]
33                .as_array()
34                .map(|arr| arr.len())
35                .unwrap_or(0);
36            println!("โœ… GET request successful, got {} models", model_count);
37        }
38        Err(e) => {
39            println!("โŒ GET request failed: {}", e);
40        }
41    }
42
43    // Test POST request (chat completion) - this has issues
44    println!("\n๐Ÿ’ฌ Test POST request (chat completion):");
45    let mut headers = HashMap::new();
46    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
47
48    let request_body = json!({
49        "model": "gpt-3.5-turbo",
50        "messages": [
51            {
52                "role": "user",
53                "content": "Say 'test' in one word."
54            }
55        ],
56        "max_tokens": 5
57    });
58
59    println!(
60        "Request body: {}",
61        serde_json::to_string_pretty(&request_body)?
62    );
63
64    match transport
65        .post::<serde_json::Value, serde_json::Value>(
66            "https://api.openai.com/v1/chat/completions",
67            Some(headers),
68            &request_body,
69        )
70        .await
71    {
72        Ok(response) => {
73            println!("โœ… POST request successful!");
74            println!("Response: {}", serde_json::to_string_pretty(&response)?);
75        }
76        Err(e) => {
77            println!("โŒ POST request failed: {}", e);
78
79            // Analyze error type
80            let error_str = e.to_string();
81            if error_str.contains("you must provide a model parameter") {
82                println!("๐Ÿ” This error is strange because we did provide the model parameter");
83                println!("   Possible reasons:");
84                println!("   1. Proxy server modified the request body");
85                println!("   2. Content-Type header issue");
86                println!("   3. JSON serialization issue");
87            }
88        }
89    }
90
91    println!("\n๐Ÿ’ก Debug Conclusion:");
92    println!("   โ€ข GET request works โ†’ authentication and network connection OK");
93    println!("   โ€ข POST request fails โ†’ may be proxy or request format issue");
94    println!("   โ€ข Recommend checking proxy server's POST request handling");
95
96    Ok(())
97}
Source

fn post<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, url: &'life1 str, headers: Option<HashMap<String, String>>, body: &'life2 T, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send POST request

Examples found in repository?
examples/debug_openai_transport.rs (lines 65-69)
7async fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("๐Ÿ” OpenAI Transport Layer Debugging");
9    println!("==================================");
10
11    let api_key = match std::env::var("OPENAI_API_KEY") {
12        Ok(key) => key,
13        Err(_) => {
14            println!("โŒ OPENAI_API_KEY not set");
15            return Ok(());
16        }
17    };
18
19    // Use our HttpTransport
20    let transport = HttpTransport::new();
21
22    // Test GET request (model list) - we know this works
23    println!("\n๐Ÿ“‹ Test GET request (model list):");
24    let mut headers = HashMap::new();
25    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
26
27    match transport
28        .get::<serde_json::Value>("https://api.openai.com/v1/models", Some(headers))
29        .await
30    {
31        Ok(response) => {
32            let model_count = response["data"]
33                .as_array()
34                .map(|arr| arr.len())
35                .unwrap_or(0);
36            println!("โœ… GET request successful, got {} models", model_count);
37        }
38        Err(e) => {
39            println!("โŒ GET request failed: {}", e);
40        }
41    }
42
43    // Test POST request (chat completion) - this has issues
44    println!("\n๐Ÿ’ฌ Test POST request (chat completion):");
45    let mut headers = HashMap::new();
46    headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
47
48    let request_body = json!({
49        "model": "gpt-3.5-turbo",
50        "messages": [
51            {
52                "role": "user",
53                "content": "Say 'test' in one word."
54            }
55        ],
56        "max_tokens": 5
57    });
58
59    println!(
60        "Request body: {}",
61        serde_json::to_string_pretty(&request_body)?
62    );
63
64    match transport
65        .post::<serde_json::Value, serde_json::Value>(
66            "https://api.openai.com/v1/chat/completions",
67            Some(headers),
68            &request_body,
69        )
70        .await
71    {
72        Ok(response) => {
73            println!("โœ… POST request successful!");
74            println!("Response: {}", serde_json::to_string_pretty(&response)?);
75        }
76        Err(e) => {
77            println!("โŒ POST request failed: {}", e);
78
79            // Analyze error type
80            let error_str = e.to_string();
81            if error_str.contains("you must provide a model parameter") {
82                println!("๐Ÿ” This error is strange because we did provide the model parameter");
83                println!("   Possible reasons:");
84                println!("   1. Proxy server modified the request body");
85                println!("   2. Content-Type header issue");
86                println!("   3. JSON serialization issue");
87            }
88        }
89    }
90
91    println!("\n๐Ÿ’ก Debug Conclusion:");
92    println!("   โ€ข GET request works โ†’ authentication and network connection OK");
93    println!("   โ€ข POST request fails โ†’ may be proxy or request format issue");
94    println!("   โ€ข Recommend checking proxy server's POST request handling");
95
96    Ok(())
97}
Source

fn put<'life0, 'life1, 'life2, 'async_trait, T, R>( &'life0 self, url: &'life1 str, headers: Option<HashMap<String, String>>, body: &'life2 T, ) -> Pin<Box<dyn Future<Output = Result<R, TransportError>> + Send + 'async_trait>>
where T: Serialize + Send + Sync + 'async_trait, R: for<'de> Deserialize<'de> + 'async_trait, Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Send PUT request

Dyn Compatibilityยง

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementorsยง