tmdb_api/movie/
now_playing.rs

1use std::borrow::Cow;
2
3use chrono::NaiveDate;
4
5use crate::common::PaginatedResult;
6
7#[derive(Clone, Debug, Default, serde::Serialize)]
8pub struct Params<'a> {
9    /// ISO 639-1 value to display translated data for the fields that support
10    /// it.
11    #[serde(skip_serializing_if = "Option::is_none")]
12    pub language: Option<Cow<'a, str>>,
13    /// Specify which page to query.
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub page: Option<u32>,
16    /// Specify a ISO 3166-1 code to filter release dates. Must be uppercase.
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub region: Option<Cow<'a, str>>,
19}
20
21impl<'a> Params<'a> {
22    pub fn set_page(&mut self, value: u32) {
23        self.page = Some(value);
24    }
25
26    pub fn with_page(mut self, value: u32) -> Self {
27        self.set_page(value);
28        self
29    }
30
31    pub fn set_language(&mut self, value: impl Into<Cow<'a, str>>) {
32        self.language = Some(value.into());
33    }
34
35    pub fn with_language(mut self, value: impl Into<Cow<'a, str>>) -> Self {
36        self.set_language(value);
37        self
38    }
39
40    pub fn set_region(&mut self, value: impl Into<Cow<'a, str>>) {
41        self.region = Some(value.into());
42    }
43
44    pub fn with_region(mut self, value: impl Into<Cow<'a, str>>) -> Self {
45        self.set_region(value);
46        self
47    }
48}
49
50#[derive(Clone, Debug, Deserialize, Serialize)]
51pub struct DateRange {
52    #[serde(deserialize_with = "crate::util::empty_string::deserialize")]
53    pub maximum: Option<NaiveDate>,
54    #[serde(deserialize_with = "crate::util::empty_string::deserialize")]
55    pub minimum: Option<NaiveDate>,
56}
57
58#[derive(Clone, Debug, Deserialize, Serialize)]
59pub struct ListMoviesNowPlayingResponse {
60    #[serde(flatten)]
61    pub inner: PaginatedResult<super::MovieShort>,
62    pub dates: DateRange,
63}
64
65impl<E: crate::client::Executor> crate::Client<E> {
66    /// Get a list of movies in theatres. This is a release type query that
67    /// looks for all movies that have a release type of 2 or 3 within the
68    /// specified date range.
69    ///
70    /// You can optionally specify a region parameter which will narrow the
71    /// search to only look for theatrical release dates within the
72    /// specified country.
73    ///
74    /// ```rust
75    /// use tmdb_api::client::Client;
76    /// use tmdb_api::client::reqwest::Client as ReqwestClient;
77    ///
78    /// #[tokio::main]
79    /// async fn main() {
80    ///     let client = Client::<ReqwestClient>::new("this-is-my-secret-token".into());
81    ///     match client.list_movies_now_playing(&Default::default()).await {
82    ///         Ok(res) => println!("found: {:#?}", res),
83    ///         Err(err) => eprintln!("error: {:?}", err),
84    ///     };
85    /// }
86    /// ```
87    pub async fn list_movies_now_playing(
88        &self,
89        params: &Params<'_>,
90    ) -> crate::Result<ListMoviesNowPlayingResponse> {
91        self.execute("/movie/now_playing", params).await
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use mockito::Matcher;
98
99    use crate::client::Client;
100    use crate::client::reqwest::Client as ReqwestClient;
101
102    #[tokio::test]
103    async fn it_works() {
104        let mut server = mockito::Server::new_async().await;
105        let client = Client::<ReqwestClient>::builder()
106            .with_api_key("secret".into())
107            .with_base_url(server.url())
108            .build()
109            .unwrap();
110
111        let _m = server
112            .mock("GET", "/movie/now_playing")
113            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
114            .with_status(200)
115            .with_header("content-type", "application/json")
116            .with_body(include_str!("../../assets/movie-now-playing.json"))
117            .create_async()
118            .await;
119
120        let result = client
121            .list_movies_now_playing(&Default::default())
122            .await
123            .unwrap();
124        assert_eq!(result.inner.page, 1);
125    }
126
127    #[tokio::test]
128    async fn invalid_api_key() {
129        let mut server = mockito::Server::new_async().await;
130        let client = Client::<ReqwestClient>::builder()
131            .with_api_key("secret".into())
132            .with_base_url(server.url())
133            .build()
134            .unwrap();
135
136        let _m = server
137            .mock("GET", "/movie/now_playing")
138            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
139            .with_status(401)
140            .with_header("content-type", "application/json")
141            .with_body(include_str!("../../assets/invalid-api-key.json"))
142            .create_async()
143            .await;
144
145        let err = client
146            .list_movies_now_playing(&Default::default())
147            .await
148            .unwrap_err();
149        let server_err = err.as_server_error().unwrap();
150        assert_eq!(server_err.status_code, 7);
151    }
152
153    #[tokio::test]
154    async fn resource_not_found() {
155        let mut server = mockito::Server::new_async().await;
156        let client = Client::<ReqwestClient>::builder()
157            .with_api_key("secret".into())
158            .with_base_url(server.url())
159            .build()
160            .unwrap();
161
162        let _m = server
163            .mock("GET", "/movie/now_playing")
164            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
165            .with_status(404)
166            .with_header("content-type", "application/json")
167            .with_body(include_str!("../../assets/resource-not-found.json"))
168            .create_async()
169            .await;
170
171        let err = client
172            .list_movies_now_playing(&Default::default())
173            .await
174            .unwrap_err();
175        let server_err = err.as_server_error().unwrap();
176        assert_eq!(server_err.status_code, 34);
177    }
178}
179
180#[cfg(all(test, feature = "integration"))]
181mod integration_tests {
182    use crate::client::Client;
183    use crate::client::reqwest::Client as ReqwestClient;
184
185    #[tokio::test]
186    async fn execute() {
187        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
188        let client = Client::<ReqwestClient>::new(secret);
189
190        let _result = client
191            .list_movies_now_playing(&Default::default())
192            .await
193            .unwrap();
194    }
195}