tmdb_api/movie/
now_playing.rs

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