shopify_api/
lib.rs

1use thiserror::Error;
2
3pub mod graphql;
4pub mod rest;
5pub mod utils;
6#[cfg(feature = "webhooks")]
7pub mod webhooks;
8
9#[derive(Clone, Debug)]
10pub struct Shopify {
11    pub api_version: String,
12    #[cfg(feature = "webhooks")]
13    shared_secret: Option<String>,
14    api_key: String,
15    query_url: String,
16    rest_url: String,
17    shop: String,
18}
19
20#[derive(Debug, Error)]
21pub enum ShopifyAPIError {
22    #[error("Connection failed")]
23    ConnectionFailed(#[from] reqwest::Error),
24
25    #[error("Response broken")]
26    ResponseBroken,
27
28    #[error("Not a JSON response: {0}")]
29    NotJson(String),
30
31    #[error("Not wanted JSON format: {0}")]
32    NotWantedJsonFormat(String),
33
34    #[error("Throttled")]
35    Throttled,
36
37    #[error("JSON parsing error: {0}")]
38    JsonParseError(#[from] serde_json::Error),
39
40    #[error("Other error: {0}")]
41    Other(String),
42}
43
44pub static VERSION: &str = "shopify_api/0.8";
45
46impl Shopify {
47    /// Create a new Shopify client
48    /// # Example
49    /// ```
50    /// use shopify_api::*;
51    /// let shopify = Shopify::new("myshop", "myapikey", String::from("2024-04"), Some("mysharedsecret"));
52    /// // or without shared secret
53    /// let shopify = Shopify::new("myshop", "myapikey", String::from("2024-04"), None);
54    /// ```
55    pub fn new(
56        shop: &str,
57        api_key: &str,
58        api_version: String,
59        #[cfg(feature = "webhooks")] shared_secret: Option<&str>,
60    ) -> Shopify {
61        let shop_domain = {
62            let mut shop_domain = shop.to_string();
63            if !shop_domain.ends_with(".myshopify.com") {
64                shop_domain.push_str(".myshopify.com");
65            }
66            shop_domain
67        };
68
69        let query_url = format!(
70            "https://{}/admin/api/{}/graphql.json",
71            shop_domain, api_version
72        );
73        let rest_url = format!("https://{}/admin/api/{}/", shop_domain, api_version);
74
75        Shopify {
76            api_version,
77            #[cfg(feature = "webhooks")]
78            shared_secret: shared_secret.map(|secret| secret.to_string()),
79            api_key: api_key.to_string(),
80            query_url,
81            rest_url,
82            shop: shop.to_string(),
83        }
84    }
85
86    /// Get the shop name
87    /// # Example
88    /// ```
89    /// use shopify_api::*;
90    /// let shopify = Shopify::new("my-shop", "my-api-key", String::from("2024-04"), Some("my-shared-secret"));
91    /// assert_eq!(shopify.get_shop(), "my-shop");
92    /// ```
93    pub fn get_shop(&self) -> &str {
94        self.shop.as_ref()
95    }
96
97    /// Set the API Key
98    /// # Example
99    /// ```
100    /// use shopify_api::*;
101    /// let mut shopify = Shopify::new("myshop", "myapikey", String::from("2024-04"), Some("mysharedsecret"));
102    /// shopify.set_api_key("newapikey");
103    /// ```
104    /// # Errors
105    /// This function returns an error if the API key is empty
106    pub fn set_api_key(&mut self, api_key: &str) -> Result<&mut Shopify, String> {
107        if api_key.is_empty() {
108            return Err("API key cannot be empty".to_string());
109        }
110
111        self.api_key = api_key.to_string();
112        Ok(self)
113    }
114
115    /// Get the query url
116    pub fn get_query_url(&self) -> &str {
117        self.query_url.as_ref()
118    }
119
120    /// Get the rest url
121    pub fn rest_url(&self) -> &str {
122        self.rest_url.as_ref()
123    }
124
125    /// Get the API endpoint
126    /// # Example
127    /// ```
128    /// use shopify_api::*;
129    /// let shopify = Shopify::new("myshop", "myapikey", String::from("2024-04"), Some("mysharedsecret"));
130    ///
131    /// assert_eq!(shopify.get_api_endpoint("products.json"), "https://myshop.myshopify.com/admin/api/2024-04/products.json");
132    /// ```
133    pub fn get_api_endpoint(&self, endpoint: &str) -> String {
134        format!("{}{}", self.rest_url(), endpoint)
135    }
136}