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#[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 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}