pinpayments/client/
async_std.rs1use std::future::{self};
2use futures::future::BoxFuture;
3
4use http_types::{Request};
5use serde::de::DeserializeOwned;
6
7use crate::error::{ErrorResponse, PinError};
8
9pub type Response<T> = BoxFuture<'static, Result<T, PinError>>;
10pub type StatusOnlyResponse = BoxFuture<'static, Result<u16, PinError>>;
11
12#[allow(dead_code)]
13#[inline(always)]
14pub(crate) fn ok<T: Send + 'static>(ok: T) -> Response<T> {
15 Box::pin(future::ready(Ok(ok)))
16}
17
18#[allow(dead_code)]
19#[inline(always)]
20pub(crate) fn err<T: Send + 'static>(err: PinError) -> Response<T> {
21 Box::pin(future::ready(Err(err)))
22}
23
24#[derive(Clone, Debug)]
25pub struct BaseClient {
26 client: surf::Client,
27}
28
29impl BaseClient {
30 pub fn new() -> Self {
31 Self { client: surf::Client::new() }
32 }
33
34 pub fn execute<T: DeserializeOwned + Send + 'static>(
35 &self,
36 request: Request,
37 ) -> Response<T> {
38 let client = self.client.clone();
41
42 Box::pin(async move {
43 let bytes = send_inner(&client, request).await?;
44 let json_deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
45 serde_path_to_error::deserialize(json_deserializer).map_err(PinError::from)
46 })
47 }
48
49 pub fn execute_status_only(
50 &self,
51 request: Request,
52 ) -> StatusOnlyResponse {
53
54 let client = self.client.clone();
55
56 Box::pin(async move {
57 Ok(send_inner_status_only(&client, request).await?)
58 })
59 }
60}
61
62async fn send_inner(
63 client: &surf::Client,
64 mut request: Request,
65) -> Result<Vec<u8>, PinError> {
66
67 let body = request.body_bytes().await?;
68
69 let mut request = request.clone();
72 request.set_body(body.clone());
73
74 let mut response = match client.send(request).await {
75 Ok(response) => {
76 response
77 },
78 Err(err) => {
79 return Err(PinError::from(err))
80 }
81 };
82
83 let status = response.status();
84
85 let bytes = response.body_bytes().await?;
86
87 if !status.is_success() {
88 let json_deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
89 let error = serde_path_to_error::deserialize(json_deserializer)
90 .map(|e: ErrorResponse| {
91 PinError::from(e)
92 })
93 .unwrap_or_else(PinError::from);
94
95 return Err(error)
96 }
97
98 Ok(bytes)
99}
100
101async fn send_inner_status_only(
102 client: &surf::Client,
103 mut request: Request,
104) -> Result<u16, PinError> {
105
106 let body = request.body_bytes().await?;
107
108 let mut request = request.clone();
109 request.set_body(body.clone());
110
111 let mut response = match client.send(request).await {
112 Ok(response) => {
113 response
114 },
115 Err(err) => {
116 return Err(PinError::from(err))
117 }
118 };
119
120 let status = response.status();
121
122 let bytes = response.body_bytes().await?;
123
124 if !status.is_success() {
125 let json_deserializer = &mut serde_json::Deserializer::from_slice(&bytes);
126 let error = serde_path_to_error::deserialize(json_deserializer)
127 .map(|e: ErrorResponse| {
128 PinError::from(e)
129 })
130 .unwrap_or_else(PinError::from);
131
132 return Err(error)
133 }
134
135 Ok(u16::from(status))
136}
137
138
139#[cfg(test)]
140mod tests {
141 use http_types::{Request, Url};
142 use httpmock::prelude::*;
143
144 use super::BaseClient;
145 use crate::{PinError};
146
147 #[async_std::test]
148 async fn user_error() {
149 let client = BaseClient::new();
150
151 let server = MockServer::start_async().await;
152
153 let mock = server.mock(|when, then| {
154 when.method(GET).path("/1/missing");
155 then.status(404).body("{
156 \"error\": \"not_found\",
157 \"error_description\": \"The requested resource was not found.\"
158 }
159 ");
160 });
161
162 let req = Request::get(Url::parse(&server.url("/1/missing")).unwrap());
163 let res = client.execute::<()>(req).await;
164
165 mock.assert_hits_async(1).await;
166
167 match res {
168 Err(PinError::PinPayments(x)) => println!("{:?}", x),
169 _ => panic!("Expected PinPayments error {:?}", res),
170 }
171 }
172}