Skip to main content

workflow_http/
native.rs

1use crate::error::Error;
2use crate::result::Result;
3
4/// Performs a GET request to `url` and returns the response body as a string.
5pub async fn get(url: impl Into<String>) -> Result<String> {
6    Request::new(url).get().await
7}
8
9/// Performs a GET request to `url` and returns the response body as raw bytes.
10pub async fn get_bytes(url: impl Into<String>) -> Result<Vec<u8>> {
11    Request::new(url).get_bytes().await
12}
13
14/// Performs a GET request to `url` and deserializes the response body from
15/// JSON into `T`.
16pub async fn get_json<T: serde::de::DeserializeOwned + 'static>(
17    url: impl Into<String>,
18) -> Result<T> {
19    Request::new(url).get_json().await
20}
21
22/// Builder for an HTTP GET request, holding the target URL and optional
23/// headers before the request is sent.
24pub struct Request {
25    /// The target URL to request.
26    pub url: String,
27    /// Optional value for the `User-Agent` request header.
28    pub user_agent: Option<String>,
29}
30
31impl Request {
32    /// Creates a new request targeting `url` with no custom headers set.
33    pub fn new(url: impl Into<String>) -> Self {
34        Self {
35            url: url.into(),
36            user_agent: None,
37        }
38    }
39
40    /// Sets the `User-Agent` header to send with the request and returns the
41    /// updated request for chaining.
42    pub fn with_user_agent(mut self, user_agent: impl Into<String>) -> Self {
43        self.user_agent = Some(user_agent.into());
44        self
45    }
46
47    /// Sends the configured GET request and returns the response body as a
48    /// string. Returns an error on a non-success HTTP status.
49    pub async fn get(self) -> Result<String> {
50        let mut req = reqwest::Client::new().get(&self.url);
51        if let Some(user_agent) = self.user_agent {
52            req = req.header("User-Agent", user_agent);
53        }
54        let resp = req.send().await?;
55        let status = resp.status();
56        let text = resp.text().await?;
57        if status.is_success() {
58            Ok(text)
59        } else {
60            Err(Error::Custom(format!("{}: {}", status, text)))
61        }
62    }
63
64    /// Sends the configured GET request and returns the response body as raw
65    /// bytes. Returns an error on a non-success HTTP status.
66    pub async fn get_bytes(self) -> Result<Vec<u8>> {
67        let mut req = reqwest::Client::new().get(&self.url);
68        if let Some(user_agent) = self.user_agent {
69            req = req.header("User-Agent", user_agent);
70        }
71        let resp = req.send().await?;
72        let status = resp.status();
73        let bytes = resp.bytes().await?;
74        if status.is_success() {
75            Ok(bytes.to_vec())
76        } else {
77            Err(Error::Custom(format!("{}: {:?}", status, bytes)))
78        }
79    }
80
81    /// Sends the configured GET request and deserializes the response body
82    /// from JSON into `T`. Returns an error on a non-success HTTP status or
83    /// if deserialization fails.
84    pub async fn get_json<T: serde::de::DeserializeOwned + 'static>(self) -> Result<T> {
85        let mut req = reqwest::Client::new().get(&self.url);
86        if let Some(user_agent) = self.user_agent {
87            req = req.header("User-Agent", user_agent);
88        }
89        let resp = req.send().await?;
90        let status = resp.status();
91        let text = resp.text().await?;
92        if status.is_success() {
93            Ok(serde_json::from_str(&text)?)
94        } else {
95            Err(Error::Custom(format!("{}: {}", status, text)))
96        }
97    }
98}