sanity_rs/
client.rs

1use super::config::SanityConfig;
2use super::{
3    error::{RequestError, URLError},
4    url::SanityURL,
5};
6use reqwest::Client as ReqwestClient;
7use std::fmt::Display;
8use url::Url;
9
10/// Creates a new SanityClient.
11///
12/// # Example
13///
14///   ```
15///   use sanity_rs::client::{ create_client, SanityClient };
16///   use sanity_rs::config::SanityConfig;
17///   use sanity_rs::error::ConfigurationError;
18///
19///   let sanity_project_id = std::env::var("SANITY_PROJECT_ID")
20///       .unwrap_or("project_id".to_string());
21///   let sanity_dataset = std::env::var("SANITY_DATASET")
22///       .unwrap_or("data_set".to_string());
23///   let config = SanityConfig::new(sanity_project_id, sanity_dataset);
24///   let mut client = create_client(config);
25///   ```
26///
27/// # Arguments
28///
29/// * `config`: A `SanityConfig` struct containing the configuration for the client.
30///
31/// # Returns
32///
33/// A `SanityClient` instance.
34///
35/// # Panics
36///
37/// Panics if the client cannot be created.  The error from `SanityClient::new` will be included in the panic message.
38pub fn create_client(config: SanityConfig) -> SanityClient {
39    match SanityClient::new(config) {
40        Ok(client) => client,
41        Err(e) => panic!("Error creating client: {:?}", e),
42    }
43}
44
45
46/// Represents the payload of a request.
47///
48/// This struct contains the URL, body, and query result of a request.
49pub struct RequestPayload {
50    /// The URL of the request.
51    pub query: Url,
52    /// The body of the request, if any.
53    pub body: Option<String>,
54    /// The result of the query, if any.  This is likely populated after processing the request.
55    pub query_result: Option<String>,
56}
57
58impl Default for RequestPayload {
59    fn default() -> Self {
60        Self {
61            query: Url::parse("https://api.sanity.io")
62                .map_err(URLError::InvalidURL)
63                .unwrap(),
64            body: None,
65            query_result: None,
66        }
67    }
68}
69
70impl RequestPayload {
71    pub fn set_body(&mut self, body: &str) -> &Self {
72        self.body = Some(body.to_string());
73        self
74    }
75}
76
77/// A client for interacting with the Sanity.io API.
78///
79/// This struct provides methods for making requests to the Sanity API.  It uses the `reqwest` crate for HTTP requests.
80pub struct SanityClient {
81    /// Configuration settings for the client.
82    pub config: SanityConfig,
83    /// The underlying HTTP client used for making requests.
84    pub client: ReqwestClient,
85    /// The payload to be sent with requests.  This is likely a struct containing data relevant to the request type.
86    pub payload: RequestPayload,
87}
88
89impl SanityClient {
90    /// Creates a new Sanity client.
91    ///
92    /// # Arguments
93    ///
94    /// * `config`: A `SanityConfig` struct containing the configuration for the client.
95    ///
96    /// # Returns
97    ///
98    /// A `Result` containing the new `SanityClient` or a `RequestError` if the URL parsing fails.
99    ///
100    /// # Errors
101    ///
102    /// This function will return an error if the URL cannot be parsed.
103    pub fn new(config: SanityConfig) -> Result<Self, RequestError> {
104        let url = SanityURL::new()
105            .host(match &config.api_host {
106                Some(host) => host.to_string(),
107                None => "api.sanity.io".to_string(),
108            })
109            .use_cdn(config.use_cdn)
110            .project_id(&config.project_id)
111            .api_version(&config.api_version)
112            .dataset(&config.dataset)
113            .build()
114            .map_err(RequestError::URLParsingError)?;
115        let mut client = Self {
116            config,
117            client: ReqwestClient::new(),
118            payload: RequestPayload::default(),
119        };
120        client.payload.query = url;
121        Ok(client)
122    }
123
124    /// Sets the request body.
125    ///
126    /// This method allows you to set the request body for subsequent use.
127    pub fn body(&mut self, body: &str) -> &mut Self {
128        self.payload.set_body(body);
129        self
130    }
131
132    /// Send a query to the Sanity API
133    pub async fn query(&mut self, body: &str) -> Result<&mut Self, RequestError> {
134        let query = &mut self.payload.query;
135        SanityURL::query(query, body);
136        let v = self.client.get(query.as_str()).send();
137        let v = v.await?.text().await?;
138        self.payload.query_result = Some(v);
139        Ok(self)
140    }
141}
142
143impl Display for SanityClient {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        f.write_str(&format!("SanityClient : {:?}", self.config.project_id))
146    }
147}