From 0cd7089455e4231c87949ce7205651a3dd3e4eb0 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Wed, 11 Sep 2024 10:30:16 +0200 Subject: [PATCH] refactor(json)!: generalize encoding/decoding (#206) * refactor: shorten variable name not as much * refactor(json)!: generalize encoding/decoding BREAKING CHANGE: Api::encode_params is gone Its was likely only meant for internal use anyway * docs(json): add doc comment * build(json): only build when serde_json available * fixup! refactor(json)!: generalize encoding/decoding * fix(error): mark as non_exhaustive --- examples/async_reply_to_message_updates.rs | 6 ++---- examples/reply_to_message_updates.rs | 6 ++---- src/api.rs | 1 + src/api/async_telegram_api_impl.rs | 23 ++++++---------------- src/api/telegram_api_impl.rs | 16 ++++----------- src/json.rs | 17 ++++++++++++++++ src/lib.rs | 18 ++++++----------- 7 files changed, 38 insertions(+), 49 deletions(-) create mode 100644 src/json.rs diff --git a/examples/async_reply_to_message_updates.rs b/examples/async_reply_to_message_updates.rs index a2e1827..40681a2 100644 --- a/examples/async_reply_to_message_updates.rs +++ b/examples/async_reply_to_message_updates.rs @@ -42,14 +42,12 @@ async fn process_message(message: Message, api: AsyncApi) { let reply_parameters = ReplyParameters::builder() .message_id(message.message_id) .build(); - let send_message_params = SendMessageParams::builder() .chat_id(message.chat.id) .text("hello") .reply_parameters(reply_parameters) .build(); - - if let Err(err) = api.send_message(&send_message_params).await { - println!("Failed to send message: {err:?}"); + if let Err(error) = api.send_message(&send_message_params).await { + println!("Failed to send message: {error:?}"); } } diff --git a/examples/reply_to_message_updates.rs b/examples/reply_to_message_updates.rs index 2c13873..8531c34 100644 --- a/examples/reply_to_message_updates.rs +++ b/examples/reply_to_message_updates.rs @@ -23,15 +23,13 @@ fn main() { let reply_parameters = ReplyParameters::builder() .message_id(message.message_id) .build(); - let send_message_params = SendMessageParams::builder() .chat_id(message.chat.id) .text("hello") .reply_parameters(reply_parameters) .build(); - - if let Err(err) = api.send_message(&send_message_params) { - println!("Failed to send message: {err:?}"); + if let Err(error) = api.send_message(&send_message_params) { + println!("Failed to send message: {error:?}"); } } update_params.offset = Some(i64::from(update.update_id) + 1); diff --git a/src/api.rs b/src/api.rs index 4503a34..50075a0 100644 --- a/src/api.rs +++ b/src/api.rs @@ -14,6 +14,7 @@ pub use telegram_api_impl::*; pub static BASE_API_URL: &str = "https://api.telegram.org/bot"; #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, thiserror::Error)] +#[non_exhaustive] #[serde(untagged)] pub enum Error { #[error("Http Error {code}: {message}")] diff --git a/src/api/async_telegram_api_impl.rs b/src/api/async_telegram_api_impl.rs index 9d83075..54a8588 100644 --- a/src/api/async_telegram_api_impl.rs +++ b/src/api/async_telegram_api_impl.rs @@ -30,13 +30,6 @@ impl AsyncApi { Self::builder().api_url(api_url).build() } - 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 where Output: serde::de::DeserializeOwned, @@ -45,18 +38,14 @@ impl AsyncApi { match response.text().await { Ok(message) => { if status_code == 200 { - Ok(Self::parse_json(&message)?) + Ok(crate::json::decode(&message)?) } else { - Err(Error::Api(Self::parse_json(&message)?)) + Err(Error::Api(crate::json::decode(&message)?)) } } - Err(e) => Err(Error::Decode(format!("Failed to decode response: {e:?}"))), + Err(error) => Err(Error::Decode(format!("{error:?}"))), } } - - fn parse_json(body: &str) -> Result { - serde_json::from_str(body).map_err(|e| Error::Decode(format!("{e:?} : {body:?}"))) - } } impl From for Error { @@ -88,7 +77,7 @@ impl AsyncTelegramApi for AsyncApi { .post(url) .header("Content-Type", "application/json"); if let Some(params) = params { - let json_string = Self::encode_params(¶ms)?; + let json_string = crate::json::encode(¶ms)?; prepared_request = prepared_request.body(json_string); }; let response = prepared_request.send().await?; @@ -105,7 +94,7 @@ impl AsyncTelegramApi for AsyncApi { Params: serde::ser::Serialize + std::fmt::Debug + std::marker::Send, Output: serde::de::DeserializeOwned, { - let json_string = Self::encode_params(¶ms)?; + let json_string = crate::json::encode(¶ms)?; let json_struct: Value = serde_json::from_str(&json_string).unwrap(); let file_keys: Vec<&str> = files.iter().map(|(key, _)| *key).collect(); let files_with_paths: Vec<(String, &str, String)> = files @@ -134,7 +123,7 @@ impl AsyncTelegramApi for AsyncApi { for (parameter_name, file_path, file_name) in files_with_paths { let file = File::open(file_path) .await - .map_err(|err| Error::Encode(err.to_string()))?; + .map_err(|error| Error::Encode(error.to_string()))?; let part = multipart::Part::stream(file).file_name(file_name); form = form.part(parameter_name, part); } diff --git a/src/api/telegram_api_impl.rs b/src/api/telegram_api_impl.rs index ca63d4d..37b09f5 100644 --- a/src/api/telegram_api_impl.rs +++ b/src/api/telegram_api_impl.rs @@ -27,21 +27,13 @@ impl Api { Self::builder().api_url(api_url).build() } - 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 where Output: serde::de::DeserializeOwned, { match response.into_string() { - 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:?}"))), + Ok(message) => crate::json::decode(&message), + Err(error) => Err(Error::Decode(format!("{error:?}"))), } } } @@ -83,7 +75,7 @@ impl TelegramApi for Api { let response = match params { None => prepared_request.call()?, Some(data) => { - let json = Self::encode_params(&data)?; + let json = crate::json::encode(&data)?; prepared_request.send_string(&json)? } }; @@ -100,7 +92,7 @@ impl TelegramApi for Api { Params: serde::ser::Serialize + std::fmt::Debug, Output: serde::de::DeserializeOwned, { - let json_string = Self::encode_params(¶ms)?; + let json_string = crate::json::encode(¶ms)?; let json_struct: Value = serde_json::from_str(&json_string).unwrap(); let file_keys: Vec<&str> = files.iter().map(|(key, _)| *key).collect(); let files_with_names: Vec<(&str, Option<&str>, PathBuf)> = files diff --git a/src/json.rs b/src/json.rs new file mode 100644 index 0000000..f172f1a --- /dev/null +++ b/src/json.rs @@ -0,0 +1,17 @@ +use crate::Error; + +/// Shortcut for [`serde_json::from_str`] with [`crate::Error`]. +pub fn decode(string: &str) -> Result +where + T: serde::de::DeserializeOwned, +{ + serde_json::from_str(string).map_err(|error| Error::Decode(format!("{error:?} : {string:?}"))) +} + +/// Shortcut for [`serde_json::to_string`] with [`crate::Error`]. +pub fn encode(value: &T) -> Result +where + T: serde::ser::Serialize + std::fmt::Debug, +{ + serde_json::to_string(value).map_err(|error| Error::Encode(format!("{error:?} : {value:?}"))) +} diff --git a/src/lib.rs b/src/lib.rs index 3912f55..ceb47e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,3 @@ -#[cfg(any(feature = "http-client", feature = "async-http-client"))] -pub mod api; - -#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] -pub mod api_traits; - -#[cfg(any(feature = "http-client", feature = "async-http-client"))] -pub use api::*; - -#[cfg(any(feature = "telegram-trait", feature = "async-telegram-trait"))] -pub use api_traits::*; - #[doc(hidden)] #[cfg(feature = "async-http-client")] pub use reqwest; @@ -18,10 +6,16 @@ pub use reqwest; #[cfg(feature = "http-client")] pub use ureq; +pub mod api; pub mod api_params; +pub mod api_traits; +#[cfg(feature = "serde_json")] +mod json; pub mod objects; mod parse_mode; +pub use api::*; pub use api_params::*; +pub use api_traits::*; pub use objects::*; pub use parse_mode::*;