tmdb_api/client/
mod.rs

1pub mod prelude;
2pub mod reqwest;
3
4use std::borrow::Cow;
5
6pub use self::prelude::Executor;
7pub type ReqwestClient = Client<reqwest::ReqwestExecutor>;
8
9const BASE_URL: &str = "https://api.themoviedb.org/3";
10
11#[derive(Debug, thiserror::Error)]
12pub enum ClientBuilderError {
13    #[error("missing api key")]
14    MissingApiKey,
15}
16
17pub struct ClientBuilder<E: prelude::Executor> {
18    base_url: Cow<'static, str>,
19    executor: Option<E>,
20    api_key: Option<String>,
21}
22
23impl<E: prelude::Executor> Default for ClientBuilder<E> {
24    fn default() -> Self {
25        Self {
26            base_url: Cow::Borrowed(BASE_URL),
27            executor: None,
28            api_key: None,
29        }
30    }
31}
32
33impl<E: prelude::Executor> ClientBuilder<E> {
34    pub fn with_base_url<U: Into<Cow<'static, str>>>(mut self, value: U) -> Self {
35        self.base_url = value.into();
36        self
37    }
38
39    pub fn set_base_url<U: Into<Cow<'static, str>>>(&mut self, value: U) {
40        self.base_url = value.into();
41    }
42
43    pub fn with_executor(mut self, executor: E) -> Self {
44        self.executor = Some(executor);
45        self
46    }
47
48    pub fn set_executor(mut self, executor: E) {
49        self.executor = Some(executor);
50    }
51
52    pub fn with_api_key(mut self, value: String) -> Self {
53        self.api_key = Some(value);
54        self
55    }
56
57    pub fn set_api_key(mut self, value: String) {
58        self.api_key = Some(value);
59    }
60
61    pub fn build(self) -> Result<Client<E>, ClientBuilderError> {
62        let base_url = self.base_url;
63        let executor = self.executor.unwrap_or_default();
64        let api_key = self.api_key.ok_or(ClientBuilderError::MissingApiKey)?;
65
66        Ok(Client {
67            executor,
68            base_url,
69            api_key,
70        })
71    }
72}
73
74#[derive(Serialize)]
75struct WithApiKey<'a, V> {
76    api_key: &'a str,
77    #[serde(flatten)]
78    inner: V,
79}
80
81/// HTTP client for TMDB
82///
83/// ```rust
84/// use tmdb_api::client::Client;
85/// use tmdb_api::client::reqwest::ReqwestExecutor;
86///
87/// let client = Client::<ReqwestExecutor>::new("this-is-my-secret-token".into());
88/// ```
89pub struct Client<E> {
90    executor: E,
91    base_url: Cow<'static, str>,
92    api_key: String,
93}
94
95impl<E: std::fmt::Debug> std::fmt::Debug for Client<E> {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        f.debug_struct(stringify!(Client))
98            .field("executor", &self.executor)
99            .field("base_url", &self.base_url)
100            .field("api_key", &"REDACTED")
101            .finish()
102    }
103}
104
105impl<E: Executor> Client<E> {
106    pub fn builder() -> ClientBuilder<E> {
107        ClientBuilder::default()
108    }
109
110    pub fn new(api_key: String) -> Self {
111        Self {
112            executor: E::default(),
113            base_url: Cow::Borrowed(BASE_URL),
114            api_key,
115        }
116    }
117
118    pub fn base_url(&self) -> &str {
119        &self.base_url
120    }
121
122    // pub async fn execute<T: serde::de::DeserializeOwned>(
123    //     &self,
124    //     path: &str,
125    //     mut params: Vec<(&str, Cow<'_, str>)>,
126    // ) -> Result<T, crate::error::Error> {
127    //     params.push(("api_key", Cow::Borrowed(self.api_key.as_str())));
128
129    //     let url = format!("{}{}", self.base_url, path);
130    //     self.executor.execute(&url, params).await
131    // }
132
133    pub async fn execute<T: serde::de::DeserializeOwned, P: serde::Serialize>(
134        &self,
135        path: &str,
136        params: &P,
137    ) -> Result<T, crate::error::Error> {
138        let url = format!("{}{}", self.base_url, path);
139        self.executor
140            .execute(
141                &url,
142                WithApiKey {
143                    api_key: &self.api_key,
144                    inner: params,
145                },
146            )
147            .await
148    }
149}