use crate::{API_VERSION, error::Error};
use cynic::{GraphQlResponse, Operation};
use serde::de::DeserializeOwned;
pub struct Client {
http: reqwest::Client,
endpoint: String,
token: String,
}
impl Client {
pub fn new(domain: impl Into<String>) -> Self {
let domain = domain.into();
let endpoint = format!("https://{}/api/{}/graphql.json", domain, API_VERSION);
Self {
http: reqwest::Client::default(),
endpoint,
token: String::new(),
}
}
pub fn token(&mut self, token: impl Into<String>) {
self.token = token.into();
}
pub async fn run<ResponseData, Vars>(
&self,
operation: Operation<ResponseData, Vars>,
) -> Result<ResponseData, Error>
where
ResponseData: DeserializeOwned + 'static,
Vars: serde::Serialize,
{
let response: GraphQlResponse<ResponseData> = self
.http
.post(&self.endpoint)
.header("X-Shopify-Storefront-Access-Token", &self.token)
.json(&operation)
.send()
.await?
.error_for_status()?
.json()
.await?;
match response.errors {
Some(errors) if !errors.is_empty() => {
let mapped = errors
.into_iter()
.map(|e| crate::error::GraphqlError {
message: e.message,
extensions: None,
})
.collect();
Err(Error::GraphQL(mapped))
}
_ => response.data.ok_or_else(|| {
Error::GraphQL(vec![crate::error::GraphqlError {
message: "Response contained no data".into(),
extensions: None,
}])
}),
}
}
}