square_rust/http/
headers.rs

1//! Represents a collection of Request Headers
2
3use std::collections::HashMap;
4
5use log::error;
6use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
7
8use crate::api::models::objects::api_error::SquareApiError;
9use crate::config;
10use crate::http::client::config::SquareHttpClientConfig;
11
12/// A collection of Request Headers
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct Headers {
15    /// The request headers as key-value pairs
16    pub headers: HashMap<String, String>,
17}
18
19impl Headers {
20    /// Indicates whether the headers include the User Agent header
21    pub fn has_user_agent(&self) -> bool {
22        self.headers.contains_key("user-agent")
23    }
24
25    /// Sets the User Agent header
26    pub fn set_user_agent(&mut self, user_agent: &str) -> Option<String> {
27        self.insert("user-agent", user_agent)
28    }
29
30    /// Adds a request header to the collection
31    pub fn insert(&mut self, header_name: &str, header_value: &str) -> Option<String> {
32        self.headers
33            .insert(String::from(header_name), String::from(header_value))
34    }
35}
36
37impl Default for Headers {
38    /// The default set of request headers
39    /// * Content-Type: application/json
40    /// * Square-Version
41    /// * accept: application/json
42    /// * user-agent
43    /// * Authorization
44    fn default() -> Self {
45        let mut headers = HashMap::new();
46
47        headers.insert(String::from("Content-Type"), String::from("application/json"));
48        headers.insert(String::from("Square-Version"), config::DEFAULT_API_VERSION.to_string());
49        headers.insert(String::from("accept"), String::from("application/json"));
50        headers.insert(String::from("user-agent"), SquareHttpClientConfig::default_user_agent());
51        headers.insert(String::from("Authorization"), config::get_default_authorization_token());
52
53        Self { headers }
54    }
55}
56
57impl TryFrom<&Headers> for HeaderMap {
58    type Error = SquareApiError;
59
60    /// Converts `Headers` into Reqwest lib's `HeaderMap`
61    fn try_from(headers: &Headers) -> Result<Self, Self::Error> {
62        let mut header_map = Self::new();
63        for (k, v) in &headers.headers {
64            let header_name = HeaderName::from_bytes(k.as_bytes()).map_err(|e| {
65                let msg = format!("Error generating {} header name: {}", k, e);
66                error!("{}", msg);
67                SquareApiError::new(&msg)
68            })?;
69            let header_value = HeaderValue::from_bytes(v.as_bytes()).map_err(|e| {
70                let msg = format!("Error generating {} header value for header {}: {}", v, k, e);
71                error!("{}", msg);
72                SquareApiError::new(&msg)
73            })?;
74            header_map.insert(header_name, header_value);
75        }
76
77        Ok(header_map)
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use std::collections::HashMap;
84
85    use reqwest::header::HeaderMap;
86
87    use crate::config;
88    use crate::http::client::config::SquareHttpClientConfig;
89    use crate::http::headers::Headers;
90
91    #[test]
92    fn headers_default() {
93        let headers = Headers::default();
94        assert_eq!(
95            headers.headers.get("Content-Type"),
96            Some(&String::from("application/json"))
97        );
98        assert_eq!(headers.headers.get("Square-Version"), Some(&String::from("2023-09-25")));
99        assert_eq!(headers.headers.get("accept"), Some(&String::from("application/json")));
100        assert_eq!(
101            headers.headers.get("user-agent"),
102            Some(&SquareHttpClientConfig::default_user_agent())
103        );
104        assert_eq!(
105            headers.headers.get("Authorization"),
106            Some(&config::get_default_authorization_token())
107        );
108        assert!(headers.has_user_agent());
109    }
110
111    #[test]
112    fn headers_has_user_agent() {
113        let mut headers = Headers::default();
114        headers.headers = HashMap::new();
115        assert!(!headers.has_user_agent());
116        headers.set_user_agent("some-user-agent");
117        assert!(headers.has_user_agent());
118    }
119
120    #[test]
121    fn headers_set_user_agent() {
122        let mut headers = Headers::default();
123        assert!(!(headers.headers.get("user-agent") == Some(&String::from("some-user-agent"))));
124        headers.set_user_agent("some-user-agent");
125        assert_eq!(
126            Some(&String::from("some-user-agent")),
127            headers.headers.get("user-agent")
128        );
129    }
130
131    #[test]
132    fn try_from_ok() {
133        assert!(HeaderMap::try_from(&Headers::default()).is_ok());
134    }
135
136    #[test]
137    fn try_from_error() {
138        let mut headers = Headers::default();
139        headers.headers = HashMap::new();
140        headers
141            .headers
142            .insert(String::from("some_faulty_code\u{1234}"), String::from("some_value"));
143        assert!(HeaderMap::try_from(&headers).is_err());
144    }
145}