whatsapp_cloud_api/
whatspapp_client.rs

1use crate::{
2    models::{MediaResponse, Message, MessageResponse, MessageStatus, MessageStatusResponse},
3    WhatsappError,
4};
5
6const FACEBOOK_GRAPH_API_BASE_URL: &str = "https://graph.facebook.com/v17.0";
7
8pub struct WhatasppClient {
9    access_token: String,
10    phone_number_id: String,
11}
12
13impl WhatasppClient {
14    pub fn new(access_token: &str, phone_number_id: &str) -> Self {
15        Self {
16            access_token: access_token.into(),
17            phone_number_id: phone_number_id.into(),
18        }
19    }
20
21    pub async fn send_message(&self, message: &Message) -> Result<MessageResponse, WhatsappError> {
22        http_client::post(&self.messages_api_url(), &self.access_token, message).await
23    }
24
25    pub async fn mark_message_as_read(
26        &self,
27        message_id: &str,
28    ) -> Result<MessageStatusResponse, WhatsappError> {
29        let message_status = MessageStatus::for_read(message_id);
30        http_client::post(
31            &self.messages_api_url(),
32            &self.access_token,
33            &message_status,
34        )
35        .await
36    }
37
38    pub async fn get_media(&self, media_id: &str) -> Result<MediaResponse, WhatsappError> {
39        http_client::get(&self.media_api_url(media_id), &self.access_token).await
40    }
41
42    fn messages_api_url(&self) -> String {
43        format!(
44            "{FACEBOOK_GRAPH_API_BASE_URL}/{}/messages",
45            self.phone_number_id
46        )
47    }
48
49    fn media_api_url(&self, media_id: &str) -> String {
50        format!("{FACEBOOK_GRAPH_API_BASE_URL}/{media_id}")
51    }
52}
53
54mod http_client {
55    use reqwest::StatusCode;
56    use serde::{de::DeserializeOwned, Serialize};
57
58    use crate::WhatsappError;
59
60    pub async fn get<U>(url: &str, bearer_token: &str) -> Result<U, WhatsappError>
61    where
62        U: DeserializeOwned,
63    {
64        let client = reqwest::Client::new();
65        let resp = client.get(url).bearer_auth(bearer_token).send().await?;
66
67        match resp.status() {
68            StatusCode::OK => {
69                let json = resp.json::<U>().await?;
70                Ok(json)
71            }
72            _ => {
73                log::warn!("{:?}", &resp);
74                let error_text = &resp.text().await?;
75                log::warn!("{:?}", &error_text);
76                Err(WhatsappError::UnexpectedError(error_text.to_string()))
77            }
78        }
79    }
80
81    pub async fn post<T, U>(url: &str, bearer_token: &str, data: &T) -> Result<U, WhatsappError>
82    where
83        T: Serialize + ?Sized,
84        U: DeserializeOwned,
85    {
86        let client = reqwest::Client::new();
87        let resp = client
88            .post(url)
89            .bearer_auth(bearer_token)
90            .json(&data)
91            .send()
92            .await?;
93
94        match resp.status() {
95            StatusCode::OK | StatusCode::CREATED => {
96                let json = resp.json::<U>().await?;
97                Ok(json)
98            }
99            _ => {
100                log::warn!("{:?}", &resp);
101                let error_text = &resp.text().await?;
102                log::warn!("{:?}", &error_text);
103                Err(WhatsappError::UnexpectedError(error_text.to_string()))
104            }
105        }
106    }
107}