1use {
2 crate::*,
3 serde::{
4 de::DeserializeOwned,
5 Deserialize,
6 Serialize,
7 },
8 std::collections::HashMap,
9};
10
11pub struct GraphqlClient {
13 requester: reqwest::Client,
14 url: String,
15 bearer_auth: Option<String>,
16}
17
18#[derive(Debug, Serialize)]
19struct GraphqlRequest {
20 query: String,
21}
22
23#[derive(Debug, Deserialize)]
24struct GraphqlResponse<D> {
25 data: Option<D>,
26 errors: Option<Vec<GraphqlError>>,
27}
28
29impl GraphqlClient {
30 pub fn new<S: Into<String>>(url: S) -> ByoResult<Self> {
32 let requester = reqwest::Client::builder().user_agent("byo/0.1").build()?;
33 Ok(Self {
34 requester,
35 url: url.into(),
36 bearer_auth: None,
37 })
38 }
39 pub fn set_bearer_auth<S: Into<String>>(
42 &mut self,
43 auth: S,
44 ) {
45 self.bearer_auth = Some(auth.into());
46 }
47 pub async fn raw<S: Into<String>>(
50 &self,
51 query: S,
52 ) -> ByoResult<reqwest::Response> {
53 let mut builder = self.requester.post(&self.url);
54 if let Some(auth) = &self.bearer_auth {
55 builder = builder.bearer_auth(auth);
56 }
57 let res = builder
58 .json(&GraphqlRequest {
59 query: query.into(),
60 })
61 .send()
62 .await?
63 .error_for_status()?;
64 Ok(res)
65 }
66 pub async fn text<S: Into<String>>(
69 &self,
70 query: S,
71 ) -> ByoResult<String> {
72 Ok(self.raw(query).await?.text().await?)
73 }
74 pub async fn get_data<S: Into<String>, Data: DeserializeOwned>(
77 &self,
78 query: S,
79 ) -> ByoResult<Data> {
80 let res = self.raw(query).await?;
81 let response: GraphqlResponse<Data> = res.json().await?;
82 if let Some(errors) = response.errors {
83 Err(ByoError::Graphql(errors))
84 } else {
85 response.data.ok_or(ByoError::NoData)
86 }
87 }
88 pub async fn get_first_item<S: Into<String>, Item: DeserializeOwned>(
92 &self,
93 query: S,
94 ) -> ByoResult<Item> {
95 let mut map: HashMap<String, Option<Item>> = self.get_data(query).await?;
96 let single = map.drain().next().and_then(|e| e.1);
97 single.ok_or(ByoError::NoData)
98 }
99}