use {
crate::*,
serde::{ de::DeserializeOwned, Deserialize, Serialize },
std:: collections::HashMap,
};
pub struct GraphqlClient {
requester: reqwest::blocking::Client,
url: String,
bearer_auth: Option<String>,
}
#[derive(Debug, Serialize)]
struct GraphqlRequest {
query: String,
}
#[derive(Debug, Deserialize)]
struct GraphqlResponse<D> {
data: Option<D>,
errors: Option<Vec<GraphqlError>>,
}
impl GraphqlClient {
pub fn new<S: Into<String>>(url: S) -> ByoResult<Self> {
let requester = reqwest::blocking::Client::builder()
.user_agent("byo/0.1")
.build()?;
Ok(Self {
requester,
url: url.into(),
bearer_auth: None,
})
}
pub fn set_bearer_auth<S: Into<String>>(&mut self, auth: S) {
self.bearer_auth = Some(auth.into());
}
pub fn raw<S: Into<String>>(&self, query: S) -> ByoResult<reqwest::blocking::Response> {
let mut builder = self.requester.post(&self.url);
if let Some(auth) = &self.bearer_auth {
builder = builder.bearer_auth(auth);
}
let res = builder
.json(&GraphqlRequest{ query: query.into() })
.send()?
.error_for_status()?;
Ok(res)
}
pub fn text<S: Into<String>>(&self, query: S) -> ByoResult<String> {
Ok(self.raw(query)?.text()?)
}
pub fn get_data<S: Into<String>, Data: DeserializeOwned>(&self, query: S) -> ByoResult<Data> {
let res = self.raw(query)?;
let response: GraphqlResponse<Data> = res.json()?;
if let Some(errors) = response.errors {
Err(ByoError::Graphql(errors))
} else {
response.data.ok_or(ByoError::NoData)
}
}
pub fn get_first_item<S: Into<String>, Item: DeserializeOwned>(&self, query: S) -> ByoResult<Item> {
let mut map: HashMap<String, Option<Item>> = self.get_data(query)?;
let single = map.drain().next().and_then(|e| e.1);
single.ok_or(ByoError::NoData)
}
}