Skip to main content

neptunium_http/
client.rs

1use reqwest::StatusCode;
2use serde_json::Deserializer;
3
4use crate::{
5    DEFAULT_API_BASE_URL, DEFAULT_USER_AGENT, VERSION,
6    endpoints::{Endpoint, ExecuteEndpointRequestError, ResponseBody},
7};
8
9/// Bot tokens have `Bot ` prefix, user tokens do not.
10#[cfg(feature = "user_api")]
11#[derive(Copy, Clone, Debug, Default)]
12pub enum TokenType {
13    #[default]
14    Bot,
15    User,
16}
17
18#[derive(Debug)]
19pub struct HttpClient {
20    pub(crate) api_base_url: String,
21    pub(crate) token: zeroize::Zeroizing<String>,
22    #[cfg(feature = "user_api")]
23    pub(crate) token_type: TokenType,
24    pub(crate) reqwest_client: reqwest::Client,
25    pub(crate) user_agent: String,
26}
27
28impl HttpClient {
29    #[must_use]
30    pub fn new(token: String, #[cfg(feature = "user_api")] token_type: TokenType) -> Self {
31        Self {
32            api_base_url: DEFAULT_API_BASE_URL.to_owned(),
33            reqwest_client: reqwest::Client::default(),
34            token: zeroize::Zeroizing::new(token),
35            #[cfg(feature = "user_api")]
36            token_type,
37            user_agent: format!("{DEFAULT_USER_AGENT}/{VERSION}"),
38        }
39    }
40
41    pub fn set_user_agent(&mut self, user_agent: String) {
42        self.user_agent = user_agent;
43    }
44
45    pub fn set_api_base_url(&mut self, url: String) {
46        self.api_base_url = url;
47    }
48
49    /// Send a request to the specified endpoint, returning the result.
50    /// # Errors
51    /// Returns an error if the response is not what is expected by the given endpoint or if a network error occurs.
52    pub async fn execute<T: Endpoint + Send>(
53        &self,
54        endpoint: T,
55    ) -> Result<T::Response, Box<ExecuteEndpointRequestError>> {
56        let request = endpoint.into_request();
57        let response = request.execute(self).await?;
58        tracing::trace!("API response: {:?}", response);
59
60        match response.status() {
61            StatusCode::OK | StatusCode::NO_CONTENT => {
62                let body = response.bytes().await?.to_vec();
63                tracing::trace!("API response body: {:?}", body);
64                ResponseBody::deserialize(body)
65            }
66            StatusCode::BAD_REQUEST => {
67                let body = String::from_utf8(response.bytes().await?.to_vec())
68                    .map_err(|e| Box::new(ExecuteEndpointRequestError::NonUtf8Bytes(e)))?;
69                let mut deserializer = Deserializer::from_str(&body);
70                let api_error = serde_path_to_error::deserialize(&mut deserializer)?;
71                Err(Box::new(ExecuteEndpointRequestError::BadRequest(api_error)))
72            }
73            StatusCode::UNAUTHORIZED => {
74                let body = String::from_utf8(response.bytes().await?.to_vec())
75                    .map_err(|e| Box::new(ExecuteEndpointRequestError::NonUtf8Bytes(e)))?;
76                let mut deserializer = Deserializer::from_str(&body);
77                let api_error = serde_path_to_error::deserialize(&mut deserializer)?;
78                Err(Box::new(ExecuteEndpointRequestError::Unauthorized(
79                    api_error,
80                )))
81            }
82            StatusCode::NOT_FOUND => {
83                let body = String::from_utf8(response.bytes().await?.to_vec())
84                    .map_err(|e| Box::new(ExecuteEndpointRequestError::NonUtf8Bytes(e)))?;
85                let mut deserializer = Deserializer::from_str(&body);
86                let api_error = serde_path_to_error::deserialize(&mut deserializer)?;
87                Err(Box::new(ExecuteEndpointRequestError::NotFound(api_error)))
88            }
89            StatusCode::FORBIDDEN => {
90                let body = String::from_utf8(response.bytes().await?.to_vec())
91                    .map_err(|e| Box::new(ExecuteEndpointRequestError::NonUtf8Bytes(e)))?;
92                let mut deserializer = Deserializer::from_str(&body);
93                let api_error = serde_path_to_error::deserialize(&mut deserializer)?;
94                Err(Box::new(ExecuteEndpointRequestError::Forbidden(api_error)))
95            }
96            StatusCode::INTERNAL_SERVER_ERROR => {
97                let body = String::from_utf8(response.bytes().await?.to_vec())
98                    .map_err(|e| Box::new(ExecuteEndpointRequestError::NonUtf8Bytes(e)))?;
99                let mut deserializer = Deserializer::from_str(&body);
100                let api_error = serde_path_to_error::deserialize(&mut deserializer)?;
101                Err(Box::new(ExecuteEndpointRequestError::InternalServerError(
102                    api_error,
103                )))
104            }
105            StatusCode::TOO_MANY_REQUESTS => {
106                let body = String::from_utf8(response.bytes().await?.to_vec())
107                    .map_err(|e| Box::new(ExecuteEndpointRequestError::NonUtf8Bytes(e)))?;
108                let mut deserializer = Deserializer::from_str(&body);
109                let api_error = serde_path_to_error::deserialize(&mut deserializer)?;
110                Err(Box::new(ExecuteEndpointRequestError::RateLimited(
111                    api_error,
112                )))
113            }
114            _ => Err(Box::new(ExecuteEndpointRequestError::ResponseNotOk(
115                response,
116            ))),
117        }
118    }
119}