square_ox/client.rs
1/*!
2The [SquareClient](crate::client::SquareClient) allows the user of the crate
3to use the [Square API](https://developer.squareup.com) in an idiomatic way.
4
5# Example: Creating a client
6In order to create a client you will need your account access token that can be found
7in the [Developer Apps](https://developer.squareup.com/apps) page for the specific
8application you are wanting to use.
9
10```rust
11 const ACCESS_TOKEN:&str = "your_square_access_token";
12
13use square_ox::client::SquareClient;
14let client = SquareClient::new(ACCESS_TOKEN);
15```
16After creating a client you will be able to use all of the clients methods.
17
18*/
19use crate::api::{SquareAPI, Verb};
20use crate::errors::SquareError;
21use crate::response::SquareResponse;
22
23use reqwest::{header, Client};
24use serde::Serialize;
25use std::default::Default;
26
27#[derive(Copy, Clone)]
28pub enum ClientMode {
29 Production,
30 Sandboxed,
31}
32
33/// The default mode we start a client in is Sandboxed
34impl Default for ClientMode {
35 fn default() -> Self {
36 Self::Sandboxed
37 }
38}
39
40/// The SquareClient contains many useful methods allowing for convenient
41/// use of the [Square API](https://developer.squareup.com).
42#[derive(Clone)]
43pub struct SquareClient {
44 access_token: String,
45 pub(crate) client_mode: ClientMode,
46}
47
48impl SquareClient {
49 /// Create a new [SquareClient](SquareClient)
50 ///
51 /// # Arguments
52 /// * `access_token` - The access token for the Square App you
53 /// want to use the client with is required.
54 ///
55 /// # Example: Create a new client
56 /// ```
57 /// const ACCESS_TOKEN:&str = "your_square_access_token";
58 /// use square_ox::client::SquareClient;
59 ///
60 /// let client = SquareClient::new(ACCESS_TOKEN);
61 /// ```
62 pub fn new(access_token: &str) -> Self {
63 Self {
64 access_token: access_token.to_string(),
65 client_mode: Default::default(),
66 }
67 }
68
69 /// Set the client to Production Mode
70 ///
71 /// # Arguments
72 /// This method takes no arguments, as by default the client will use SandBox Mode.
73 ///
74 /// # Example
75 /// ```
76 /// const ACCESS_TOKEN:&str = "your_square_access_token";
77 ///
78 /// use square_ox::client::SquareClient;
79 /// let client = SquareClient::new(ACCESS_TOKEN).production();
80 /// ```
81 pub fn production(self) -> Self {
82 Self {
83 access_token: self.access_token,
84 client_mode: ClientMode::Production,
85 }
86 }
87
88 /// Sends a request to a given [SquareAPI](crate::api::SquareAPI)
89 /// # Arguments
90 /// * `api` - The [SquareAPI](crate::api::SquareAPI) to send the request to
91 /// * `body` - The json that will be included in the request.
92 /// All types that meet the conditions to be deserialized to JSON are accepted.
93 ///
94 /// # Example:
95 /// ```
96 /// use env_logger::Builder;
97 /// async {
98 /// use square_ox::{
99 /// api::{
100 /// Verb, SquareAPI, payment::PaymentRequest
101 /// },
102 /// client,
103 /// builder::Builder
104 /// };
105 /// const ACCESS_TOKEN:&str = "your_square_access_token";
106 /// let payment = Builder::from(PaymentRequest::default()).build().await;
107 ///
108 /// let client = client::SquareClient::new(ACCESS_TOKEN);
109 /// client.request( Verb::POST, SquareAPI::Payments("".to_string()), Some(&payment), None).await.expect("");
110 /// };
111 ///
112 /// ```
113 pub async fn request<T>(
114 &self,
115 verb: Verb,
116 endpoint: SquareAPI,
117 json: Option<&T>,
118 parameters: Option<Vec<(String, String)>>,
119 ) -> Result<SquareResponse, SquareError>
120 where
121 T: Serialize + ?Sized,
122 {
123 let url = self.endpoint(endpoint).clone();
124 let authorization_header = format!("Bearer {}", &self.access_token);
125
126 // Add the headers to the request
127 let mut headers = header::HeaderMap::new();
128 headers.insert(
129 header::AUTHORIZATION,
130 header::HeaderValue::from_str(&authorization_header)?,
131 );
132
133 // Create a client with the appropriate headers
134 let client = Client::builder().default_headers(headers).build()?;
135
136 println!("url: {}", &url);
137
138 // Send the request to the Square API, and get the response
139 let mut builder = match verb {
140 Verb::GET => client.get(&url),
141 Verb::POST => client.post(&url),
142 Verb::PUT => client.put(&url),
143 Verb::PATCH => client.patch(&url),
144 Verb::DELETE => client.delete(&url),
145 };
146
147 // Add query parameters if there are any
148 if let Some(parameters) = parameters {
149 builder = builder.query(¶meters);
150 }
151
152 // Add a json body if there is one
153 if let Some(json) = json {
154 builder = builder.json(json)
155 }
156
157 // Deserialize the response into a SquareResponse
158 let response: SquareResponse = builder.send().await?.json().await?;
159
160 // TODO debug code!
161 // let response = builder.send().await?.text().await?;
162 // println!("{:?}", response);
163 // let response: SquareResponse = serde_json::from_str(&response)?;
164 // println!("{:?}", response);
165
166 // handle the possibility of an error being returned by the Square API
167 if response.errors.is_some() && response.errors.as_ref().unwrap().len() > 0 {
168 return Err(SquareError::from(response.errors))
169 }
170
171 Ok(response)
172 }
173}