diff --git a/examples/api_trait_implementation.rs b/examples/api_trait_implementation.rs index 6eebf05..102e5d8 100644 --- a/examples/api_trait_implementation.rs +++ b/examples/api_trait_implementation.rs @@ -49,11 +49,15 @@ impl From for Error { impl TelegramApi for Api { type Error = Error; - fn request( + fn request( &self, method: &str, - params: Option, - ) -> Result { + params: Option, + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned, + { let url = format!("{}/{method}", self.api_url); let request_builder = Request::post(url).header("Content-Type", "application/json"); @@ -68,28 +72,32 @@ impl TelegramApi for Api { let text = response.text().map_err(|error| Error::Http { code: 500, - message: error.to_string(), + message: format!("{error:?}"), })?; - let parsed_result: Result = serde_json::from_str(&text); - - parsed_result.map_err(|_| match serde_json::from_str::(&text) { - Ok(result) => Error::Api(result), - Err(error) => Error::Http { - code: 500, - message: format!("{error:?}"), - }, + serde_json::from_str(&text).map_err(|_| { + match serde_json::from_str::(&text) { + Ok(result) => Error::Api(result), + Err(error) => Error::Http { + code: 500, + message: format!("{error:?}"), + }, + } }) } // isahc doesn't support multipart uploads // https://github.com/sagebind/isahc/issues/14 - fn request_with_form_data( + fn request_with_form_data( &self, _method: &str, - _params: T1, + _params: Params, _files: Vec<(&str, PathBuf)>, - ) -> Result { + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned, + { let message = "isahc doesn't support form data requests".to_string(); Err(Error::Http { code: 500, message }) } diff --git a/src/client_reqwest.rs b/src/client_reqwest.rs index 4b2d8d7..d602de7 100644 --- a/src/client_reqwest.rs +++ b/src/client_reqwest.rs @@ -26,19 +26,21 @@ impl AsyncApi { } /// Create a new `AsyncApi`. You can use [`AsyncApi::builder`] for more options. - pub fn new_url>(api_url: T) -> Self { + pub fn new_url>(api_url: S) -> Self { Self::builder().api_url(api_url).build() } - pub fn encode_params( - params: &T, - ) -> Result { + pub fn encode_params(params: &Params) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + { serde_json::to_string(params).map_err(|e| Error::Encode(format!("{e:?} : {params:?}"))) } - pub async fn decode_response( - response: reqwest::Response, - ) -> Result { + pub async fn decode_response(response: reqwest::Response) -> Result + where + Output: serde::de::DeserializeOwned, + { let status_code = response.status().as_u16(); match response.text().await { Ok(message) => { @@ -48,11 +50,11 @@ impl AsyncApi { Err(Error::Api(Self::parse_json(&message)?)) } } - Err(error) => Err(Error::Decode(error.to_string())), + Err(error) => Err(Error::Decode(format!("{error:?}"))), } } - fn parse_json(body: &str) -> Result { + fn parse_json(body: &str) -> Result { serde_json::from_str(body).map_err(|e| Error::Decode(format!("{e:?} : {body:?}"))) } } @@ -61,44 +63,38 @@ impl AsyncApi { impl AsyncTelegramApi for AsyncApi { type Error = Error; - async fn request< - T1: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, - T2: serde::de::DeserializeOwned, - >( + async fn request( &self, method: &str, - params: Option, - ) -> Result { + params: Option, + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, + Output: serde::de::DeserializeOwned, + { let url = format!("{}/{method}", self.api_url); - let mut prepared_request = self .client .post(url) .header("Content-Type", "application/json"); - - prepared_request = if let Some(data) = params { - let json_string = Self::encode_params(&data)?; - - prepared_request.body(json_string) - } else { - prepared_request + if let Some(params) = params { + let json_string = Self::encode_params(¶ms)?; + prepared_request = prepared_request.body(json_string); }; - let response = prepared_request.send().await?; - let parsed_response: T2 = Self::decode_response(response).await?; - - Ok(parsed_response) + Self::decode_response(response).await } - async fn request_with_form_data< - T1: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, - T2: serde::de::DeserializeOwned, - >( + async fn request_with_form_data( &self, method: &str, - params: T1, + params: Params, files: Vec<(&str, PathBuf)>, - ) -> Result { + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, + Output: serde::de::DeserializeOwned, + { let json_string = Self::encode_params(¶ms)?; let json_struct: Value = serde_json::from_str(&json_string).unwrap(); let file_keys: Vec<&str> = files.iter().map(|(key, _)| *key).collect(); @@ -136,9 +132,7 @@ impl AsyncTelegramApi for AsyncApi { let url = format!("{}/{method}", self.api_url); let response = self.client.post(url).multipart(form).send().await?; - let parsed_response: T2 = Self::decode_response(response).await?; - - Ok(parsed_response) + Self::decode_response(response).await } } diff --git a/src/client_ureq.rs b/src/client_ureq.rs index 49963d4..6ce0b57 100644 --- a/src/client_ureq.rs +++ b/src/client_ureq.rs @@ -23,33 +23,25 @@ impl Api { } /// Create a new `Api`. You can use [`Api::builder`] for more options. - pub fn new_url>(api_url: T) -> Self { + pub fn new_url>(api_url: S) -> Self { Self::builder().api_url(api_url).build() } - pub fn encode_params( - params: &T, - ) -> Result { + pub fn encode_params(params: &Params) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + { serde_json::to_string(params).map_err(|e| Error::Encode(format!("{e:?} : {params:?}"))) } - pub fn decode_response(response: Response) -> Result { + pub fn decode_response(response: Response) -> Result + where + Output: serde::de::DeserializeOwned, + { match response.into_string() { - Ok(message) => { - let json_result: Result = serde_json::from_str(&message); - - match json_result { - Ok(result) => Ok(result), - Err(e) => { - let err = Error::Decode(format!("{e:?} : {message:?}")); - Err(err) - } - } - } - Err(e) => { - let err = Error::Decode(format!("Failed to decode response: {e:?}")); - Err(err) - } + Ok(message) => serde_json::from_str(&message) + .map_err(|error| Error::Decode(format!("{error:?} : {message:?}"))), + Err(e) => Err(Error::Decode(format!("Failed to decode response: {e:?}"))), } } } @@ -57,17 +49,16 @@ impl Api { impl TelegramApi for Api { type Error = Error; - fn request( - &self, - method: &str, - params: Option, - ) -> Result { + fn request(&self, method: &str, params: Option) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned, + { let url = format!("{}/{method}", self.api_url); let prepared_request = self .request_agent .post(&url) .set("Content-Type", "application/json"); - let response = match params { None => prepared_request.call()?, Some(data) => { @@ -75,21 +66,19 @@ impl TelegramApi for Api { prepared_request.send_string(&json)? } }; - - let parsed_response: T2 = Self::decode_response(response)?; - - Ok(parsed_response) + Self::decode_response(response) } - fn request_with_form_data< - T1: serde::ser::Serialize + std::fmt::Debug, - T2: serde::de::DeserializeOwned, - >( + fn request_with_form_data( &self, method: &str, - params: T1, + params: Params, files: Vec<(&str, PathBuf)>, - ) -> Result { + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned, + { let json_string = Self::encode_params(¶ms)?; let json_struct: Value = serde_json::from_str(&json_string).unwrap(); let file_keys: Vec<&str> = files.iter().map(|(key, _)| *key).collect(); @@ -131,10 +120,7 @@ impl TelegramApi for Api { &format!("multipart/form-data; boundary={}", form_data.boundary()), ) .send(form_data)?; - - let parsed_response: T2 = Self::decode_response(response)?; - - Ok(parsed_response) + Self::decode_response(response) } } diff --git a/src/trait_async.rs b/src/trait_async.rs index dbc77cd..566dc9b 100644 --- a/src/trait_async.rs +++ b/src/trait_async.rs @@ -257,7 +257,7 @@ pub trait AsyncTelegramApi { let mut new_params = params.clone(); new_params.media = new_medias; - let files_with_str_names: Vec<(&str, PathBuf)> = files + let files_with_str_names = files .iter() .map(|(key, path)| (key.as_str(), path.clone())) .collect(); @@ -965,7 +965,7 @@ pub trait AsyncTelegramApi { let mut new_params = params.clone(); new_params.media = new_media; - let files_with_str_names: Vec<(&str, PathBuf)> = files + let files_with_str_names = files .iter() .map(|(key, path)| (key.as_str(), path.clone())) .collect(); @@ -1066,7 +1066,7 @@ pub trait AsyncTelegramApi { let mut new_params = params.clone(); new_params.stickers = new_stickers; - let files_with_str_names: Vec<(&str, PathBuf)> = files + let files_with_str_names = files .iter() .map(|(key, path)| (key.as_str(), path.clone())) .collect(); @@ -1283,33 +1283,33 @@ pub trait AsyncTelegramApi { .await } - async fn request_without_body( - &self, - method: &str, - ) -> Result { + async fn request_without_body(&self, method: &str) -> Result + where + Output: serde::de::DeserializeOwned, + { let params: Option<()> = None; - self.request(method, params).await } - async fn request< - T1: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, - T2: serde::de::DeserializeOwned, - >( + async fn request( &self, method: &str, - params: Option, - ) -> Result; + params: Option, + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, + Output: serde::de::DeserializeOwned; - async fn request_with_possible_form_data< - T1: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, - T2: serde::de::DeserializeOwned, - >( + async fn request_with_possible_form_data( &self, method_name: &str, - params: T1, + params: Params, files: Vec<(&str, PathBuf)>, - ) -> Result { + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, + Output: serde::de::DeserializeOwned, + { if files.is_empty() { self.request(method_name, Some(params)).await } else { @@ -1318,13 +1318,13 @@ pub trait AsyncTelegramApi { } } - async fn request_with_form_data< - T1: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, - T2: serde::de::DeserializeOwned, - >( + async fn request_with_form_data( &self, method: &str, - params: T1, + params: Params, files: Vec<(&str, PathBuf)>, - ) -> Result; + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, + Output: serde::de::DeserializeOwned; } diff --git a/src/trait_sync.rs b/src/trait_sync.rs index 7485299..33ab359 100644 --- a/src/trait_sync.rs +++ b/src/trait_sync.rs @@ -244,7 +244,7 @@ pub trait TelegramApi { let mut new_params = params.clone(); new_params.media = new_medias; - let files_with_str_names: Vec<(&str, PathBuf)> = files + let files_with_str_names = files .iter() .map(|(key, path)| (key.as_str(), path.clone())) .collect(); @@ -915,7 +915,7 @@ pub trait TelegramApi { let mut new_params = params.clone(); new_params.media = new_media; - let files_with_str_names: Vec<(&str, PathBuf)> = files + let files_with_str_names = files .iter() .map(|(key, path)| (key.as_str(), path.clone())) .collect(); @@ -1010,7 +1010,7 @@ pub trait TelegramApi { let mut new_params = params.clone(); new_params.stickers = new_stickers; - let files_with_str_names: Vec<(&str, PathBuf)> = files + let files_with_str_names = files .iter() .map(|(key, path)| (key.as_str(), path.clone())) .collect(); @@ -1218,24 +1218,24 @@ pub trait TelegramApi { self.request("unpinAllGeneralForumTopicMessages", Some(params)) } - fn request_without_body( - &self, - method: &str, - ) -> Result { + fn request_without_body(&self, method: &str) -> Result + where + Output: serde::de::DeserializeOwned, + { let params: Option<()> = None; - self.request(method, params) } - fn request_with_possible_form_data< - T1: serde::ser::Serialize + std::fmt::Debug, - T2: serde::de::DeserializeOwned, - >( + fn request_with_possible_form_data( &self, method_name: &str, - params: &T1, + params: &Params, files: Vec<(&str, PathBuf)>, - ) -> Result { + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned, + { if files.is_empty() { self.request(method_name, Some(params)) } else { @@ -1243,19 +1243,22 @@ pub trait TelegramApi { } } - fn request_with_form_data< - T1: serde::ser::Serialize + std::fmt::Debug, - T2: serde::de::DeserializeOwned, - >( + fn request_with_form_data( &self, method: &str, - params: T1, + params: Params, files: Vec<(&str, PathBuf)>, - ) -> Result; + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned; - fn request( + fn request( &self, method: &str, - params: Option, - ) -> Result; + params: Option, + ) -> Result + where + Params: serde::ser::Serialize + std::fmt::Debug, + Output: serde::de::DeserializeOwned; }