mercadopago_sdk_rust/
lib.rs1pub mod card_tokens;
76pub mod common_types;
77pub mod errors;
78pub mod helpers;
79pub mod payments;
80pub mod preferences;
81pub mod webhooks;
82
83use std::marker::PhantomData;
84
85use futures::future::err;
86use futures::TryFutureExt;
87use oauth2::basic::BasicClient;
88use oauth2::reqwest::async_http_client;
89use oauth2::{
90 AccessToken, AuthType, AuthUrl, ClientId, ClientSecret, Scope, TokenResponse, TokenUrl,
91};
92use reqwest::{Client, Method, RequestBuilder};
93use serde::de::DeserializeOwned;
94
95use crate::card_tokens::requests::CardTokenOptions;
96use crate::card_tokens::responses::CardTokenResponse;
97use crate::errors::{ApiError, SDKError};
98use crate::payments::requests::CreatePaymentPayload;
99use crate::preferences::requests::CheckoutProPreferences;
100use crate::preferences::responses::CheckoutProPreferencesResponse;
101
102const API_BASE_URL: &str = "https://api.mercadopago.com";
103
104#[derive(Debug)]
106pub struct MercadoPagoSDKBuilder {}
107
108impl MercadoPagoSDKBuilder {
109 async fn authorize<T: ToString>(
110 client_id: T,
111 client_secret: T,
112 ) -> Result<MercadoPagoSDK, SDKError> {
113 let client = BasicClient::new(
114 ClientId::new(client_id.to_string()),
115 Some(ClientSecret::new(client_secret.to_string())),
116 AuthUrl::new("https://auth.mercadopago.com/authorization".to_string()).unwrap(),
117 Some(TokenUrl::new("https://api.mercadopago.com/oauth/token".to_string()).unwrap()),
118 )
119 .set_auth_type(AuthType::BasicAuth);
120
121 let token_response = client
122 .exchange_client_credentials()
123 .add_scope(Scope::new("offline_access".to_string()))
124 .request_async(async_http_client)
125 .await
126 .unwrap();
127
128 Ok(MercadoPagoSDK {
129 http_client: Default::default(),
130 access_token: token_response.access_token().clone(),
131 })
132 }
133
134 pub fn with_token<T: ToString>(client_access_token: T) -> MercadoPagoSDK {
136 MercadoPagoSDK {
137 http_client: Default::default(),
138 access_token: AccessToken::new(client_access_token.to_string()),
139 }
140 }
141}
142
143#[derive(Debug)]
144pub struct MercadoPagoSDK {
145 pub(crate) http_client: Client,
146 pub(crate) access_token: AccessToken,
147}
148
149#[derive(Debug)]
150pub struct SDKRequest<'a, RP> {
151 http_client: &'a Client,
152 access_token: &'a AccessToken,
153 request: RequestBuilder,
154 response_type: PhantomData<RP>,
155}
156
157impl<'a, RP> SDKRequest<'a, RP> {
158 pub async fn execute(self) -> Result<RP, SDKError>
160 where
161 RP: DeserializeOwned,
162 {
163 let request = self
164 .request
165 .bearer_auth(self.access_token.secret())
166 .build()
167 .unwrap();
168 let response = self
169 .http_client
170 .execute(request)
171 .and_then(|c| c.text())
172 .await?;
173 eprintln!("response = {}", response);
174
175 let error_jd = serde_json::from_str::<ApiError>(&*response);
177 if let Ok(err) = error_jd {
178 eprintln!("err = {:#?}", err);
179 return Err(SDKError::GenericError);
180 }
181
182 let jd = &mut serde_json::Deserializer::from_str(&*response);
183 let res: Result<RP, _> = serde_path_to_error::deserialize(jd);
184
185 match res {
186 Ok(deserialized_resp) => Ok(deserialized_resp),
187 Err(wow) => {
188 println!("{:?}", wow.path());
189 eprintln!("Error = {:#?}", wow);
190 Err(SDKError::GenericError)
191 }
192 }
193 }
194}
195
196impl MercadoPagoSDK {
197 pub fn create_preferences_checkout_pro(
198 &self,
199 opts: CheckoutProPreferences,
200 ) -> Result<SDKRequest<CheckoutProPreferencesResponse>, SDKError> {
201 if opts.validate() {}
202
203 let request = self
204 .http_client
205 .request(
206 Method::POST,
207 API_BASE_URL.to_string() + "/checkout/preferences",
208 )
209 .json(&opts);
210
211 Ok(SDKRequest {
212 http_client: &self.http_client,
213 access_token: &self.access_token,
214 request,
215 response_type: PhantomData::<_>,
216 })
217 }
218
219 pub fn create_card_token(
224 &self,
225 opts: CardTokenOptions,
226 ) -> Result<SDKRequest<CardTokenResponse>, SDKError> {
227 let url = format!(
228 "{}/v1/card_tokens?public_key={}",
229 API_BASE_URL,
230 opts.public_key.as_deref().unwrap_or("")
231 );
232
233 let request = self.http_client.request(Method::POST, url).json(&opts);
234
235 Ok(SDKRequest {
236 http_client: &self.http_client,
237 access_token: &self.access_token,
238 request,
239 response_type: PhantomData::<_>,
240 })
241 }
242
243 pub fn create_payment(
244 &self,
245 opts: CreatePaymentPayload,
246 ) -> Result<SDKRequest<CheckoutProPreferencesResponse>, SDKError> {
247 let request = self
248 .http_client
249 .request(Method::POST, "/payments")
250 .json(&opts);
251
252 Ok(SDKRequest {
253 http_client: &self.http_client,
254 access_token: &self.access_token,
255 request,
256 response_type: PhantomData::<CheckoutProPreferencesResponse>,
257 })
258 }
259}