mangadex_api/v5/cover/cover_id/
get.rs

1//! Builder for the cover view endpoint.
2//!
3//! <https://api.mangadex.org/docs/swagger.html#/Cover/get-cover-id>
4//!
5//! # Examples
6//!
7//! ```rust
8//! use uuid::Uuid;
9//!
10//! use mangadex_api::v5::MangaDexClient;
11//!
12//! # async fn run() -> anyhow::Result<()> {
13//! let client = MangaDexClient::default();
14//!
15//! let cover_id = Uuid::new_v4();
16//! let cover_res = client
17//!     .cover()
18//!     .cover_id(cover_id)
19//!     .get()
20//!     .send()
21//!     .await?;
22//!
23//! println!("cover: {:?}", cover_res);
24//! # Ok(())
25//! # }
26//! ```
27
28use derive_builder::Builder;
29use serde::Serialize;
30use uuid::Uuid;
31
32use crate::HttpClientRef;
33use mangadex_api_schema::v5::CoverResponse;
34use mangadex_api_types::ReferenceExpansionResource;
35
36#[cfg_attr(
37    feature = "deserializable-endpoint",
38    derive(serde::Deserialize, getset::Getters, getset::Setters)
39)]
40#[derive(Debug, Serialize, Clone, Builder)]
41#[serde(rename_all = "camelCase")]
42#[builder(
43    setter(into, strip_option),
44    build_fn(error = "mangadex_api_types::error::BuilderError")
45)]
46pub struct GetCover {
47    /// This should never be set manually as this is only for internal use.
48    #[doc(hidden)]
49    #[serde(skip)]
50    #[builder(pattern = "immutable")]
51    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
52    pub http_client: HttpClientRef,
53
54    /// Manga **or** Cover ID.
55    #[serde(skip_serializing)]
56    pub cover_id: Uuid,
57
58    #[builder(setter(each = "include"), default)]
59    pub includes: Vec<ReferenceExpansionResource>,
60}
61
62endpoint! {
63    GET ("/cover/{}", cover_id),
64    #[query] GetCover,
65    #[flatten_result] CoverResponse,
66    GetCoverBuilder
67}
68
69#[cfg(test)]
70mod tests {
71    use fake::faker::lorem::en::Sentence;
72    use fake::Fake;
73    use serde_json::json;
74    use time::OffsetDateTime;
75    use url::Url;
76    use uuid::Uuid;
77    use wiremock::matchers::{method, path_regex};
78    use wiremock::{Mock, MockServer, ResponseTemplate};
79
80    use crate::{HttpClient, MangaDexClient};
81    use mangadex_api_types::error::Error;
82    use mangadex_api_types::{Language, MangaDexDateTime};
83
84    #[tokio::test]
85    async fn get_cover_fires_a_request_to_base_url() -> anyhow::Result<()> {
86        let mock_server = MockServer::start().await;
87        let http_client = HttpClient::builder()
88            .base_url(Url::parse(&mock_server.uri())?)
89            .build()?;
90        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
91
92        let cover_id = Uuid::new_v4();
93        let description: String = Sentence(1..3).fake();
94
95        let datetime = MangaDexDateTime::new(&OffsetDateTime::now_utc());
96
97        let response_body = json!({
98            "result": "ok",
99            "response": "entity",
100            "data": {
101                "id": cover_id,
102                "type": "cover_art",
103                "attributes": {
104                    "volume": "1",
105                    "fileName": "1.jpg",
106                    "description": description,
107                    "locale": "en",
108                    "version": 1,
109                    "createdAt": datetime.to_string(),
110                    "updatedAt": datetime.to_string(),
111
112                },
113                "relationships": []
114            }
115        });
116
117        Mock::given(method("GET"))
118            .and(path_regex(r"/cover/[0-9a-fA-F-]+"))
119            .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
120            .expect(1)
121            .mount(&mock_server)
122            .await;
123
124        let res = mangadex_client
125            .cover()
126            .cover_id(cover_id)
127            .get()
128            .send()
129            .await?;
130
131        assert_eq!(res.data.id, cover_id);
132        assert_eq!(res.data.attributes.volume, Some("1".to_string()));
133        assert_eq!(res.data.attributes.file_name, "1.jpg".to_string());
134        assert_eq!(res.data.attributes.description, description);
135        assert_eq!(res.data.attributes.locale, Some(Language::English));
136        assert_eq!(res.data.attributes.version, 1);
137        assert_eq!(
138            res.data.attributes.created_at.to_string(),
139            datetime.to_string()
140        );
141        assert_eq!(
142            res.data.attributes.updated_at.as_ref().unwrap().to_string(),
143            datetime.to_string()
144        );
145
146        Ok(())
147    }
148
149    #[tokio::test]
150    async fn get_chapter_handles_404() -> anyhow::Result<()> {
151        let mock_server = MockServer::start().await;
152        let http_client: HttpClient = HttpClient::builder()
153            .base_url(Url::parse(&mock_server.uri())?)
154            .build()?;
155        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
156
157        let cover_id = Uuid::new_v4();
158        let error_id = Uuid::new_v4();
159
160        let response_body = json!({
161            "result": "error",
162            "errors": [{
163                "id": error_id.to_string(),
164                "status": 404,
165                "title": "Not found",
166                "detail": "Cover could not be found"
167            }]
168        });
169
170        Mock::given(method("GET"))
171            .and(path_regex(r"/cover/[0-9a-fA-F-]+"))
172            .respond_with(ResponseTemplate::new(404).set_body_json(response_body))
173            .expect(1)
174            .mount(&mock_server)
175            .await;
176
177        let res = mangadex_client
178            .cover()
179            .cover_id(cover_id)
180            .get()
181            .send()
182            .await
183            .expect_err("expected error");
184
185        if let Error::Api(errors) = res {
186            assert_eq!(errors.errors.len(), 1);
187
188            assert_eq!(errors.errors[0].id, error_id);
189            assert_eq!(errors.errors[0].status, 404);
190            assert_eq!(errors.errors[0].title, Some("Not found".to_string()));
191            assert_eq!(
192                errors.errors[0].detail,
193                Some("Cover could not be found".to_string())
194            );
195        }
196
197        Ok(())
198    }
199}