Skip to main content

logtail_rust/http_client/
base_client.rs

1use super::{HttpClient, LogtailError};
2use reqwest::header::{HeaderMap, HeaderValue};
3use serde_json::Value;
4
5pub struct ReqwestClient;
6
7impl HttpClient for ReqwestClient {
8    async fn post_json(
9        &self,
10        url: &str,
11        body: &Value,
12        extra_headers: Option<HeaderMap>,
13    ) -> Result<Option<Value>, LogtailError> {
14        let mut header_map = HeaderMap::new();
15
16        if let Some(value) = extra_headers {
17            header_map.extend(value.iter().map(|(k, v)| (k.clone(), v.clone())))
18        }
19
20        let client = reqwest::Client::new();
21
22        let response = client
23            .post(url)
24            .headers(build_headers(Some(header_map)))
25            .json(body)
26            .send()
27            .await?;
28
29        if response.status().is_success() {
30            let body_bytes = response.bytes().await?;
31
32            if !body_bytes.is_empty() {
33                let result_value: Value = serde_json::from_slice(&body_bytes)?;
34                return Ok(Some(result_value));
35            }
36
37            Ok(None)
38        } else {
39            let status = response.status().as_u16();
40            Err(LogtailError::Http {
41                status,
42                message: format!("HTTP request failed with status {}", status),
43            })
44        }
45    }
46}
47
48fn build_headers(input_headers: Option<HeaderMap>) -> HeaderMap {
49    let mut headers = HeaderMap::new();
50    if let Some(extra) = input_headers {
51        headers = extra;
52    }
53
54    headers.insert("Accept", HeaderValue::from_static("application/json"));
55
56    headers
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn build_headers_none_adds_accept() {
65        let headers = build_headers(None);
66        assert_eq!(
67            headers.get("Accept").unwrap(),
68            HeaderValue::from_static("application/json")
69        );
70        assert_eq!(headers.len(), 1);
71    }
72
73    #[test]
74    fn build_headers_merges_extra_headers() {
75        let mut extra = HeaderMap::new();
76        extra.insert("Authorization", HeaderValue::from_static("Bearer token123"));
77
78        let headers = build_headers(Some(extra));
79        assert_eq!(
80            headers.get("Authorization").unwrap(),
81            HeaderValue::from_static("Bearer token123")
82        );
83        assert_eq!(
84            headers.get("Accept").unwrap(),
85            HeaderValue::from_static("application/json")
86        );
87        assert_eq!(headers.len(), 2);
88    }
89
90    #[test]
91    fn build_headers_accept_overwrites_extra() {
92        let mut extra = HeaderMap::new();
93        extra.insert("Accept", HeaderValue::from_static("text/plain"));
94
95        let headers = build_headers(Some(extra));
96        assert_eq!(
97            headers.get("Accept").unwrap(),
98            HeaderValue::from_static("application/json")
99        );
100    }
101}