parse_rs/
requests.rs

1// use crate::acl::ParseACL; // Unused
2use crate::error::ParseError;
3
4use reqwest::{Method, Response as HttpResponse};
5use serde::{de::DeserializeOwned, Serialize};
6use serde_json::Value;
7
8impl crate::Parse {
9    // New internal helper to send a pre-built request and process its response.
10    pub(crate) async fn _send_and_process_response<R: DeserializeOwned + Send + 'static>(
11        &self, // Keep &self for potential future use, though not strictly needed by current logic
12        response: HttpResponse, // Changed from request_builder
13        _endpoint_context: &str, // Added for logging/error context
14    ) -> Result<R, ParseError> {
15        let status = response.status();
16        let response_url = response.url().to_string(); // For logging
17
18        // Try to get the body as text first for logging, then consume for JSON
19        let response_text = response.text().await.map_err(ParseError::ReqwestError)?;
20
21        if status.is_success() {
22            if response_text.is_empty() || response_text == "{}" {
23                // Handle cases where R is (), expecting no content or empty object
24                if std::any::TypeId::of::<R>() == std::any::TypeId::of::<()>() {
25                    // Attempt to deserialize from "null" as a convention for empty successful responses
26                    // This allows `()` to be a valid response type for 204 No Content or empty {} body.
27                    return serde_json::from_str("null").map_err(ParseError::JsonError);
28                }
29            }
30            // Attempt to deserialize the response body
31            serde_json::from_str::<R>(&response_text).map_err(|e| {
32                log::error!(
33                    "JSON Deserialization failed for successful response from '{}'. Status: {}. Error: {}. Body: {}",
34                    response_url,
35                    status,
36                    e,
37                    &response_text // Log the problematic text
38                );
39                ParseError::JsonDeserializationFailed(format!(
40                    "Failed to deserialize successful response from '{}': {}. Body: {}",
41                    response_url, e, &response_text
42                ))
43            })
44        } else {
45            // Attempt to parse the error response body as JSON
46            let parsed_body: Value = match serde_json::from_str(&response_text) {
47                Ok(json_val) => json_val,
48                Err(_) => {
49                    // If parsing the error body as JSON fails, create a generic error
50                    log::warn!(
51                        "Failed to parse error response body as JSON from '{}'. Status: {}. Body: {}",
52                        response_url, status, &response_text
53                    );
54                    Value::Object(serde_json::Map::from_iter(vec![
55                        (
56                            "error".to_string(),
57                            Value::String(format!("HTTP Error {} with non-JSON body", status)),
58                        ),
59                        (
60                            "body_snippet".to_string(),
61                            Value::String(response_text.chars().take(100).collect()),
62                        ),
63                    ]))
64                }
65            };
66            Err(ParseError::from_response(status.as_u16(), parsed_body))
67        }
68    }
69
70    // Public HTTP method wrappers
71    pub async fn get<R: DeserializeOwned + Send + 'static>(
72        &self,
73        endpoint: &str,
74    ) -> Result<R, ParseError> {
75        self._request(Method::GET, endpoint, None::<&Value>, false, None)
76            .await
77    }
78
79    pub async fn post<T: Serialize + Send + Sync, R: DeserializeOwned + Send + 'static>(
80        &self,
81        endpoint: &str,
82        data: &T,
83    ) -> Result<R, ParseError> {
84        self._request(Method::POST, endpoint, Some(data), false, None)
85            .await
86    }
87
88    pub async fn put<T: Serialize + Send + Sync, R: DeserializeOwned + Send + 'static>(
89        &self,
90        endpoint: &str,
91        data: &T,
92    ) -> Result<R, ParseError> {
93        self._request(Method::PUT, endpoint, Some(data), false, None)
94            .await
95    }
96
97    pub async fn delete<R: DeserializeOwned + Send + 'static>(
98        &self,
99        endpoint: &str,
100    ) -> Result<R, ParseError> {
101        self._request(Method::DELETE, endpoint, None::<&Value>, false, None)
102            .await
103    }
104}