whatsapp_cloud_api/
whatsapp_client.rs1use crate::{
2 models::{
3 CodeMethod, CodeRequestParams, CodeVerifyParams, MediaResponse, Message, MessageResponse,
4 MessageStatus, MessageStatusResponse, PhoneNumberResponse,
5 },
6 WhatsappError,
7};
8
9const FACEBOOK_GRAPH_API_BASE_URL: &str = "https://graph.facebook.com";
10
11#[deprecated(note = "whatsapp-cloud-api has moved to the `whatsapp` crate: https://crates.io/crates/whatsapp")]
12pub struct WhatsappClient {
13 version: String,
14 access_token: String,
15 phone_number_id: String,
16}
17
18impl WhatsappClient {
19 pub fn new(access_token: &str, phone_number_id: &str) -> Self {
20 Self {
21 version: "v26.0".into(),
22 access_token: access_token.into(),
23 phone_number_id: phone_number_id.into(),
24 }
25 }
26
27 pub fn version(&mut self) -> &str {
28 &self.version
29 }
30
31 pub fn set_version(&mut self, version: &str) {
32 self.version = version.into();
33 }
34
35 pub fn set_access_token(&mut self, access_token: &str) {
36 self.access_token = access_token.into();
37 }
38
39 pub fn set_phone_number_id(&mut self, phone_number_id: &str) {
40 self.phone_number_id = phone_number_id.into();
41 }
42
43 pub async fn send_message(&self, message: &Message) -> Result<MessageResponse, WhatsappError> {
44 http_client::post(&self.messages_api_url(), &self.access_token, message).await
45 }
46
47 pub async fn request_code(
48 &self,
49 code_method: CodeMethod,
50 language: &str,
51 ) -> Result<PhoneNumberResponse, WhatsappError> {
52 let params = CodeRequestParams {
53 code_method,
54 language: language.into(),
55 };
56 http_client::post(&self.request_code_api_url(), &self.access_token, ¶ms).await
57 }
58
59 pub async fn verify_code(&self, code: &str) -> Result<PhoneNumberResponse, WhatsappError> {
60 let params = CodeVerifyParams { code: code.into() };
61 http_client::post(&self.verify_code_api_url(), &self.access_token, ¶ms).await
62 }
63
64 pub async fn mark_message_as_read(
65 &self,
66 message_id: &str,
67 ) -> Result<MessageStatusResponse, WhatsappError> {
68 let message_status = MessageStatus::for_read(message_id);
69 http_client::post(
70 &self.messages_api_url(),
71 &self.access_token,
72 &message_status,
73 )
74 .await
75 }
76
77 pub async fn get_media(&self, media_id: &str) -> Result<MediaResponse, WhatsappError> {
78 http_client::get(&self.media_api_url(media_id), &self.access_token).await
79 }
80
81 fn facebook_api_version_url(&self) -> String {
82 format!("{FACEBOOK_GRAPH_API_BASE_URL}/{}", self.version)
83 }
84
85 fn messages_api_url(&self) -> String {
86 format!(
87 "{}/{}/messages",
88 self.facebook_api_version_url(),
89 self.phone_number_id
90 )
91 }
92
93 fn media_api_url(&self, media_id: &str) -> String {
94 format!("{}/{media_id}", self.facebook_api_version_url())
95 }
96
97 fn request_code_api_url(&self) -> String {
98 format!(
99 "{}/{}/request_code",
100 self.facebook_api_version_url(),
101 self.phone_number_id
102 )
103 }
104
105 fn verify_code_api_url(&self) -> String {
106 format!(
107 "{}/{}/verify_code",
108 self.facebook_api_version_url(),
109 self.phone_number_id
110 )
111 }
112}
113
114mod http_client {
115 use reqwest::StatusCode;
116 use serde::{de::DeserializeOwned, Serialize};
117
118 use crate::WhatsappError;
119
120 pub async fn get<U>(url: &str, bearer_token: &str) -> Result<U, WhatsappError>
121 where
122 U: DeserializeOwned,
123 {
124 let client = reqwest::Client::new();
125 let resp = client.get(url).bearer_auth(bearer_token).send().await?;
126
127 match resp.status() {
128 StatusCode::OK => {
129 let json = resp.json::<U>().await?;
130 Ok(json)
131 }
132 _ => {
133 log::warn!("{:?}", &resp);
134 let error_text = &resp.text().await?;
135 log::warn!("{:?}", &error_text);
136 Err(WhatsappError::UnexpectedError(error_text.to_string()))
137 }
138 }
139 }
140
141 pub async fn post<T, U>(url: &str, bearer_token: &str, data: &T) -> Result<U, WhatsappError>
142 where
143 T: Serialize + ?Sized,
144 U: DeserializeOwned,
145 {
146 let client = reqwest::Client::new();
147 let resp = client
148 .post(url)
149 .bearer_auth(bearer_token)
150 .json(&data)
151 .send()
152 .await?;
153
154 match resp.status() {
155 StatusCode::OK | StatusCode::CREATED => {
156 let json = resp.json::<U>().await?;
157 Ok(json)
158 }
159 _ => {
160 log::warn!("{:?}", &resp);
161 let error_text = &resp.text().await?;
162 log::warn!("{:?}", &error_text);
163 Err(WhatsappError::UnexpectedError(error_text.to_string()))
164 }
165 }
166 }
167}