mod bulk_query;
pub mod types;
use crate::{
utils::{self, read_json_tree, ReadJsonTreeSteps},
Shopify, ShopifyAPIError,
};
#[cfg(feature = "graphql-client")]
use graphql_client::{GraphQLQuery, Response as GraphQLResponse};
use reqwest::{Client, Response};
async fn shopify_graphql_query<VariablesType, ReturnType>(
(shopify, graphql_query, variables, json_finder): &(
&Shopify,
&str,
&VariablesType,
&Vec<ReadJsonTreeSteps<'_>>,
),
) -> Result<ReturnType, ShopifyAPIError>
where
VariablesType: serde::Serialize,
ReturnType: serde::de::DeserializeOwned,
{
let client = reqwest::Client::new();
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Content-Type", "application/json".parse().unwrap());
headers.insert("X-Shopify-Access-Token", shopify.api_key.parse().unwrap());
let req_body: &serde_json::Value = &serde_json::json!({
"query": graphql_query,
"variables": variables
});
let res: Response = client
.post(shopify.get_query_url())
.headers(headers)
.body(req_body.to_string())
.send()
.await?;
let body = res.text().await;
if body.is_err() {
return Err(ShopifyAPIError::ResponseBroken);
}
let body = body.unwrap();
log::debug!(
"shopify (url: {}) response: {body} \n With body: {}",
shopify.get_query_url(),
req_body.to_string()
);
let json: serde_json::Value =
serde_json::from_str(&body).map_err(ShopifyAPIError::JsonParseError)?;
if let Some(error) = json["errors"]["01"]["extensions"]["code"].as_str() {
if error == "THROTTLED" {
return Err(ShopifyAPIError::Throttled);
}
}
let json = match read_json_tree(&json, json_finder) {
Ok(v) => v,
Err(_) => {
return Err(ShopifyAPIError::NotWantedJsonFormat(json.to_string()));
}
};
let end_json: ReturnType = match serde_json::from_value(json.to_owned()) {
Ok(v) => v,
Err(_) => {
return Err(ShopifyAPIError::NotWantedJsonFormat(json.to_string()));
}
};
Ok(end_json)
}
impl Shopify {
pub async fn graphql_query<ReturnType, VariablesType>(
&self,
graphql_query: &str,
variables: &VariablesType,
json_finder: &Vec<ReadJsonTreeSteps<'_>>,
) -> Result<ReturnType, ShopifyAPIError>
where
ReturnType: serde::de::DeserializeOwned,
VariablesType: serde::Serialize,
{
let args = (self, graphql_query, variables, json_finder);
let response_json = utils::retry_async(
10,
shopify_graphql_query::<VariablesType, ReturnType>,
&args,
)
.await?;
Ok(response_json)
}
#[cfg(feature = "graphql-client")]
pub async fn post_graphql<Q: GraphQLQuery>(
&self,
variables: Q::Variables,
) -> Result<GraphQLResponse<Q::ResponseData>, reqwest::Error> {
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("Content-Type", "application/json".parse().unwrap());
headers.insert("X-Shopify-Access-Token", self.api_key.parse().unwrap());
let client = Client::builder()
.user_agent(crate::VERSION)
.default_headers(headers)
.build()?;
let body = Q::build_query(variables);
let reqwest_response = client.post(self.get_query_url()).json(&body).send().await?;
reqwest_response.json().await
}
}