amazon_sp_api/
general.rs

1use std::borrow::Borrow;
2use crate::error_handling::Errors;
3use reqwest::header::HeaderMap;
4use serde::Deserialize;
5use serde_json::json;
6use std::time::{ Instant};
7use reqwest::{ Response, Url};
8const ENDPOINT_NA: &str = "https://sellingpartnerapi-na.amazon.com";
9const ENDPOINT_EU: &str = "https://sellingpartnerapi-eu.amazon.com";
10const ENDPOINT_FE: &str = "https://sellingpartnerapi-fe.amazon.com";
11
12pub enum CountryMarketplace {
13    Canada,
14    UnitedStates,
15    Mexico,
16    Brazil,
17    Ireland,
18    Spain,
19    UnitedKingdom,
20    France,
21    Belgium,
22    Netherlands,
23    Germany,
24    Italy,
25    Sweden,
26    SouthAfrica,
27    Poland,
28    Egypt,
29    Turkey,
30    SaudiArabia,
31    UnitedArabEmirates,
32    India,
33    Singapore,
34    Australia,
35    Japan,
36}
37pub struct ClientInformation {
38    pub refresh_token: String,
39    pub client_id: String,
40    pub client_secret: String,
41    pub country_marketplace: CountryMarketplace,
42}
43#[allow(dead_code)]
44#[derive(Deserialize)]
45struct AccessToken {
46    access_token: String,
47    expires_in: i64,
48    refresh_token: String,
49    token_type: String,
50}
51
52impl ClientInformation {
53    async fn get_access_token(&self, x: &reqwest::Client) -> Result<AccessToken, Errors> {
54        let ff = json!({
55        "refresh_token": self.refresh_token,
56        "client_id": self.client_id,
57        "client_secret":self.client_secret,
58        "grant_type": "refresh_token"});
59
60        Ok(x.request(
61            reqwest::Method::POST,
62            "https://api.amazon.com/auth/o2/token",
63        )
64        .body(ff.to_string())
65        .send()
66        .await?
67        .json::<AccessToken>()
68        .await?)
69    }
70}
71impl CountryMarketplace {
72    /// Returns the marketplace ID and the endpoint for the given country.
73    pub fn details(&self) -> (&'static str, &'static str) {
74        match self {
75            CountryMarketplace::Canada => ("A2EUQ1WTGCTBG2", ENDPOINT_NA),
76            CountryMarketplace::UnitedStates => ("ATVPDKIKX0DER", ENDPOINT_NA),
77            CountryMarketplace::Mexico => ("A1AM78C64UM0Y8", ENDPOINT_NA),
78            CountryMarketplace::Brazil => ("A2Q3Y263D00KWC", ENDPOINT_NA),
79            CountryMarketplace::Ireland => ("A28R8C7NBKEWEA", ENDPOINT_EU),
80            CountryMarketplace::Spain => ("A1RKKUPIHCS9HS", ENDPOINT_EU),
81            CountryMarketplace::UnitedKingdom => ("A1F83G8C2ARO7P", ENDPOINT_EU),
82            CountryMarketplace::France => ("A13V1IB3VIYZZH", ENDPOINT_EU),
83            CountryMarketplace::Belgium => ("AMEN7PMS3EDWL", ENDPOINT_EU),
84            CountryMarketplace::Netherlands => ("A1805IZSGTT6HS", ENDPOINT_EU),
85            CountryMarketplace::Germany => ("A1PA6795UKMFR9", ENDPOINT_EU),
86            CountryMarketplace::Italy => ("APJ6JRA9NG5V4", ENDPOINT_EU),
87            CountryMarketplace::Sweden => ("A2NODRKZP88ZB9", ENDPOINT_EU),
88            CountryMarketplace::SouthAfrica => ("AE08WJ6YKNBMC", ENDPOINT_EU),
89            CountryMarketplace::Poland => ("A1C3SOZRARQ6R3", ENDPOINT_EU),
90            CountryMarketplace::Egypt => ("ARBP9OOSHTCHU", ENDPOINT_EU),
91            CountryMarketplace::Turkey => ("A33AVAJ2PDY3EV", ENDPOINT_EU),
92            CountryMarketplace::SaudiArabia => ("A17E79C6D8DWNP", ENDPOINT_EU),
93            CountryMarketplace::UnitedArabEmirates => ("A2VIGQ35RCS4UG", ENDPOINT_EU),
94            CountryMarketplace::India => ("A21TJRUUN4KGV", ENDPOINT_EU),
95            CountryMarketplace::Singapore => ("A19VAU5U5O7RUS", ENDPOINT_FE),
96            CountryMarketplace::Australia => ("A39IBJ37TRP1C6", ENDPOINT_FE),
97            CountryMarketplace::Japan => ("A1VC38T7YXB528", ENDPOINT_FE),
98        }
99    }
100}
101#[macro_export] macro_rules! enum_to_string {
102    ($($type:ty)*) => {
103       stringify!($($type)*)
104    };
105}
106#[allow(dead_code)]
107pub struct Client {
108    access_token: AccessToken,
109    client_information: ClientInformation,
110    last_refresh: Instant,
111    reqwest_client: reqwest::Client,
112}
113impl Client {
114    async fn refresh_token(&mut self) {
115        match self
116            .client_information
117            .get_access_token(&self.reqwest_client).await
118        {
119            Ok(o) => self.access_token = o,
120            Err(_) => {}
121        }
122    }
123    pub async fn new(client: ClientInformation) -> Result<Self, Errors> {
124        let reqwest_client = reqwest::Client::new();
125        match client.get_access_token(&reqwest_client).await {
126            Ok(o) => Ok(Client {
127                access_token: o,
128                client_information: client,
129                last_refresh: Instant::now(),
130                reqwest_client,
131            }),
132            Err(e) => Err(e),
133        }
134    }
135    async fn check_validity(&mut self) {
136        if Instant::now().duration_since(self.last_refresh).as_secs()
137            > (self.access_token.expires_in - 10) as u64
138        {
139            self.refresh_token().await;
140        }
141    }
142    fn create_header(&mut self) -> HeaderMap {
143        let mut header_map = HeaderMap::new();
144        header_map.insert("x-amz-access-token", self.access_token.access_token.parse().unwrap());
145        header_map.insert("CONTENT_TYPE", "application/json".parse().unwrap());
146        header_map.insert("user-agent", "Amazon-SP-API-rs 0.1.0".parse().unwrap());
147        header_map
148    }
149    pub async fn make_request<I, K, V>(&mut self, path: &str, method: reqwest::Method, parameters: Option<I>) -> Result<Response, Errors>
150    where
151        I: IntoIterator + std::fmt::Debug+ Clone,
152        I::Item: Borrow<(K, V)>,
153        K: AsRef<str>,
154        V: AsRef<str>,
155    {
156        //parameters.( ("marketplaceIds", self.client_information.country_marketplace.details().0));
157        if let Some(params) = parameters {
158            Ok(self.reqwest_client.request(method, Url::parse_with_params(format!("{}{}", self.client_information.country_marketplace.details().1, path).as_str(), params)?).headers(self.create_header()).send().await?)
159        }  else {
160            Ok(self.reqwest_client.request(method, Url::parse(format!("{}{}", self.client_information.country_marketplace.details().1, path).as_str())?).headers(self.create_header()).send().await?)
161
162        }
163        //Ok(self.reqwest_client.request(method, Url::parse_with_params(format!("{}{}",self.client_information.country_marketplace.details().1, path).as_str(), parameters)?).headers(self.create_header()).send().await?)
164    }
165    pub async fn make_request_w_body<I, K, V>(&mut self, path: &str, method: reqwest::Method, parameters: Option<I>, body: String) -> Result<Response, Errors>
166    where
167        I: IntoIterator + std::fmt::Debug,
168        I::Item: Borrow<(K, V)>,
169        K: AsRef<str>,
170        V: AsRef<str>,
171    {
172        if let Some(param) = parameters {
173            Ok(self.reqwest_client.request(method, Url::parse_with_params(format!("{}{}",self.client_information.country_marketplace.details().1, path).as_str(), param)?).headers(self.create_header()).body(body).send().await?)
174        } else {
175            Ok(self.reqwest_client.request(method, Url::parse(format!("{}{}",self.client_information.country_marketplace.details().1, path).as_str())?).headers(self.create_header()).body(body).send().await?)
176        }
177    }
178
179}