openai_rust_sdk/api/base/
response_handlers.rs

1//! Response handling and error conversion functionality
2
3use crate::api::base::client::HttpClient;
4use crate::error::{OpenAIError, Result};
5use serde::de::DeserializeOwned;
6
7impl HttpClient {
8    /// Handle error response by extracting text and parsing as API error
9    pub(crate) async fn handle_error_response<T>(
10        &self,
11        response: reqwest::Response,
12        status: reqwest::StatusCode,
13    ) -> Result<T> {
14        let error_text = response
15            .text()
16            .await
17            .unwrap_or_else(|_| "Unknown error".to_string());
18
19        // Try to parse as API error response
20        serde_json::from_str::<crate::error::ApiErrorResponse>(&error_text).map_or_else(
21            |_| {
22                Err(OpenAIError::ApiError {
23                    status: status.as_u16(),
24                    message: error_text,
25                })
26            },
27            |api_error| Err(OpenAIError::from_api_response(status.as_u16(), api_error)),
28        )
29    }
30
31    /// Handle API response and convert to the desired type
32    pub async fn handle_response<T>(&self, response: reqwest::Response) -> Result<T>
33    where
34        T: DeserializeOwned,
35    {
36        let status = response.status();
37
38        if status.is_success() {
39            let text = response.text().await?;
40            serde_json::from_str(&text).map_err(|e| {
41                OpenAIError::ParseError(format!("Failed to parse response: {e}. Response: {text}"))
42            })
43        } else {
44            self.handle_error_response(response, status).await
45        }
46    }
47
48    /// Extract raw content from a successful response
49    async fn extract_raw_content<F, R>(
50        &self,
51        response: reqwest::Response,
52        status: reqwest::StatusCode,
53        extractor: F,
54        error_context: &str,
55    ) -> Result<R>
56    where
57        F: FnOnce(
58            reqwest::Response,
59        )
60            -> futures::future::BoxFuture<'static, std::result::Result<R, reqwest::Error>>,
61        R: 'static,
62    {
63        if status.is_success() {
64            extractor(response).await.map_err(crate::map_err!(
65                RequestError,
66                error_context,
67                to_string
68            ))
69        } else {
70            self.handle_error_response(response, status).await
71        }
72    }
73
74    /// Make a GET request and return raw text content
75    pub async fn get_text(&self, path: &str) -> Result<String> {
76        let url = self.build_simple_url(path);
77        let headers = self.build_headers()?;
78
79        let response = self.client().get(&url).headers(headers).send().await?;
80        let status = response.status();
81
82        self.extract_raw_content(
83            response,
84            status,
85            |r| Box::pin(async move { r.text().await }),
86            "Failed to read response text",
87        )
88        .await
89    }
90
91    /// Make a GET request and return raw bytes
92    pub async fn get_bytes(&self, path: &str) -> Result<Vec<u8>> {
93        let url = self.build_simple_url(path);
94        let headers = self.build_headers()?;
95
96        let response = self.client().get(&url).headers(headers).send().await?;
97        let status = response.status();
98
99        self.extract_raw_content(
100            response,
101            status,
102            |r| Box::pin(async move { r.bytes().await.map(|b| b.to_vec()) }),
103            "Failed to read response bytes",
104        )
105        .await
106    }
107
108    /// Make a POST request and return raw bytes with content type
109    pub async fn post_bytes_with_content_type<B>(
110        &self,
111        path: &str,
112        body: &B,
113    ) -> Result<(Vec<u8>, String)>
114    where
115        B: serde::Serialize,
116    {
117        let url = self.build_simple_url(path);
118        let headers = self.build_headers()?;
119
120        let response = self
121            .client()
122            .post(&url)
123            .headers(headers)
124            .json(body)
125            .send()
126            .await?;
127
128        let status = response.status();
129        if status.is_success() {
130            let content_type = response
131                .headers()
132                .get("content-type")
133                .and_then(|v| v.to_str().ok())
134                .unwrap_or("application/octet-stream")
135                .to_string();
136
137            let bytes = response.bytes().await.map_err(|e| {
138                OpenAIError::RequestError(format!("Failed to read response bytes: {e}"))
139            })?;
140
141            Ok((bytes.to_vec(), content_type))
142        } else {
143            self.handle_error_response(response, status).await
144        }
145    }
146}