reqwest_builder/
serialization.rs

1use crate::errors::ReqwestBuilderError;
2use http::HeaderMap;
3use serde::Serialize;
4use std::collections::HashMap;
5
6/// Convert a serializable type to form parameters with proper error handling
7pub fn serialize_to_form_params<T: Serialize>(
8    data: &T,
9) -> std::result::Result<HashMap<String, String>, ReqwestBuilderError> {
10    let value = serde_json::to_value(data)?;
11
12    let obj = value.as_object().ok_or_else(|| {
13        ReqwestBuilderError::SerializationError("Data must serialize to a JSON object".to_string())
14    })?;
15
16    let mut params = HashMap::new();
17    for (key, val) in obj {
18        let value_str = match val {
19            serde_json::Value::String(s) => s.clone(),
20            serde_json::Value::Number(n) => n.to_string(),
21            serde_json::Value::Bool(b) => b.to_string(),
22            serde_json::Value::Null => continue, // Skip null values
23            _ => val.to_string(),                // Arrays and objects as JSON strings
24        };
25        params.insert(key.clone(), value_str);
26    }
27
28    Ok(params)
29}
30
31/// Convert serializable headers to HeaderMap with proper error handling
32pub fn serialize_to_header_map<T: Serialize>(
33    headers: &T,
34) -> std::result::Result<HeaderMap, ReqwestBuilderError> {
35    let mut header_map = HeaderMap::new();
36    let value = serde_json::to_value(headers)?;
37
38    let obj = value.as_object().ok_or_else(|| {
39        ReqwestBuilderError::SerializationError(
40            "Headers must serialize to a JSON object".to_string(),
41        )
42    })?;
43
44    for (key, val) in obj {
45        if let Some(val_str) = val.as_str() {
46            let header_name = http::HeaderName::from_bytes(key.as_bytes()).map_err(|e| {
47                ReqwestBuilderError::HeaderError {
48                    key: key.clone(),
49                    value: val_str.to_string(),
50                    source: format!("Invalid header name: {}", e),
51                }
52            })?;
53
54            let header_value = http::HeaderValue::from_str(val_str).map_err(|e| {
55                ReqwestBuilderError::HeaderError {
56                    key: key.clone(),
57                    value: val_str.to_string(),
58                    source: format!("Invalid header value: {}", e),
59                }
60            })?;
61
62            header_map.insert(header_name, header_value);
63        } else {
64            return Err(ReqwestBuilderError::HeaderError {
65                key: key.clone(),
66                value: val.to_string(),
67                source: "Header value must be a string".to_string(),
68            });
69        }
70    }
71
72    Ok(header_map)
73}
74
75/// Construct a URL by combining base URL and endpoint
76pub fn construct_url(base_url: &url::Url, endpoint: &str) -> String {
77    let base_str = base_url.as_str().trim_end_matches('/');
78    let endpoint_str = endpoint.trim_start_matches('/');
79
80    if endpoint_str.is_empty() {
81        return base_str.to_string();
82    }
83
84    format!("{base_str}/{endpoint_str}")
85}