tmdb_api/movie/
now_playing.rs

1use chrono::NaiveDate;
2use std::borrow::Cow;
3
4use crate::common::PaginatedResult;
5
6/// Get a list of movies in theatres. This is a release type query that looks for
7/// all movies that have a release type of 2 or 3 within the specified date range.
8///
9/// You can optionally specify a region parameter which will narrow the search
10/// to only look for theatrical release dates within the specified country.
11///
12/// ```rust
13/// use tmdb_api::prelude::Command;
14/// use tmdb_api::client::Client;
15/// use tmdb_api::client::reqwest::ReqwestExecutor;
16/// use tmdb_api::movie::now_playing::MovieNowPlaying;
17///
18/// #[tokio::main]
19/// async fn main() {
20///     let client = Client::<ReqwestExecutor>::new("this-is-my-secret-token".into());
21///     let result = MovieNowPlaying::default().execute(&client).await;
22///     match result {
23///         Ok(res) => println!("found: {:#?}", res),
24///         Err(err) => eprintln!("error: {:?}", err),
25///     };
26/// }
27/// ```
28#[derive(Clone, Debug, Default)]
29pub struct MovieNowPlaying {
30    /// ISO 639-1 value to display translated data for the fields that support it.
31    pub language: Option<String>,
32    /// Specify which page to query.
33    pub page: Option<u32>,
34    /// Specify a ISO 3166-1 code to filter release dates. Must be uppercase.
35    pub region: Option<String>,
36}
37
38impl MovieNowPlaying {
39    pub fn with_language(mut self, value: Option<String>) -> Self {
40        self.language = value;
41        self
42    }
43
44    pub fn with_page(mut self, value: Option<u32>) -> Self {
45        self.page = value;
46        self
47    }
48
49    pub fn with_region(mut self, value: Option<String>) -> Self {
50        self.region = value;
51        self
52    }
53}
54
55#[derive(Clone, Debug, Deserialize, Serialize)]
56pub struct DateRange {
57    #[serde(deserialize_with = "crate::util::empty_string::deserialize")]
58    pub maximum: Option<NaiveDate>,
59    #[serde(deserialize_with = "crate::util::empty_string::deserialize")]
60    pub minimum: Option<NaiveDate>,
61}
62
63#[derive(Clone, Debug, Deserialize, Serialize)]
64pub struct MovieNowPlayingResult {
65    #[serde(flatten)]
66    pub inner: PaginatedResult<super::MovieShort>,
67    pub dates: DateRange,
68}
69
70impl crate::prelude::Command for MovieNowPlaying {
71    type Output = MovieNowPlayingResult;
72
73    fn path(&self) -> Cow<'static, str> {
74        Cow::Borrowed("/movie/now_playing")
75    }
76
77    fn params(&self) -> Vec<(&'static str, Cow<'_, str>)> {
78        let mut res = Vec::new();
79        if let Some(ref language) = self.language {
80            res.push(("language", Cow::Borrowed(language.as_str())))
81        }
82        if let Some(ref page) = self.page {
83            res.push(("page", Cow::Owned(page.to_string())))
84        }
85        if let Some(ref region) = self.region {
86            res.push(("region", Cow::Borrowed(region.as_str())))
87        }
88        res
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::MovieNowPlaying;
95    use crate::client::Client;
96    use crate::client::reqwest::ReqwestExecutor;
97    use crate::prelude::Command;
98    use mockito::Matcher;
99
100    #[tokio::test]
101    async fn it_works() {
102        let mut server = mockito::Server::new_async().await;
103        let client = Client::<ReqwestExecutor>::builder()
104            .with_api_key("secret".into())
105            .with_base_url(server.url())
106            .build()
107            .unwrap();
108
109        let _m = server
110            .mock("GET", "/movie/now_playing")
111            .match_query(Matcher::UrlEncoded("api_key".into(), "secret".into()))
112            .with_status(200)
113            .with_header("content-type", "application/json")
114            .with_body(include_str!("../../assets/movie-now-playing.json"))
115            .create_async()
116            .await;
117
118        let result = MovieNowPlaying::default().execute(&client).await.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::<ReqwestExecutor>::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 = MovieNowPlaying::default()
141            .execute(&client)
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::<ReqwestExecutor>::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 = MovieNowPlaying::default()
167            .execute(&client)
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 super::MovieNowPlaying;
178    use crate::client::Client;
179    use crate::client::reqwest::ReqwestExecutor;
180    use crate::prelude::Command;
181
182    #[tokio::test]
183    async fn execute() {
184        let secret = std::env::var("TMDB_TOKEN_V3").unwrap();
185        let client = Client::<ReqwestExecutor>::new(secret);
186
187        let _result = MovieNowPlaying::default().execute(&client).await.unwrap();
188    }
189}