mangadex_api/v5/manga/manga_id/relation/
get.rs

1//! Builder for fetching a Manga's relations.
2//!
3//! This fetches the related Manga for the specified Manga such as spin-offs, doujinshis, and more.
4//!
5//! <https://api.mangadex.org/docs/swagger.html#/Manga/get-manga-relation>
6//!
7//! # Examples
8//!
9//! ```rust
10//! use uuid::Uuid;
11//!
12//! use mangadex_api::v5::MangaDexClient;
13//!
14//! # async fn run() -> anyhow::Result<()> {
15//! let client = MangaDexClient::default();
16//!
17//! let manga_id = Uuid::new_v4();
18//! let res = client
19//!     .manga()
20//!     .manga_id(manga_id)
21//!     .relation()
22//!     .get()
23//!     .send()
24//!     .await?;
25//!
26//! println!("manga relation list: {:?}", res);
27//! # Ok(())
28//! # }
29//! ```
30
31use derive_builder::Builder;
32use serde::Serialize;
33use uuid::Uuid;
34
35use crate::HttpClientRef;
36use mangadex_api_schema::v5::MangaRelationListResponse;
37use mangadex_api_types::ReferenceExpansionResource;
38
39#[cfg_attr(
40    feature = "deserializable-endpoint",
41    derive(serde::Deserialize, getset::Getters, getset::Setters)
42)]
43#[derive(Debug, Serialize, Clone, Builder)]
44#[serde(rename_all = "camelCase")]
45#[builder(
46    setter(into, strip_option),
47    build_fn(error = "mangadex_api_types::error::BuilderError")
48)]
49pub struct ListMangaRelations {
50    /// This should never be set manually as this is only for internal use.
51    #[doc(hidden)]
52    #[serde(skip)]
53    #[builder(pattern = "immutable")]
54    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
55    pub http_client: HttpClientRef,
56
57    #[serde(skip_serializing)]
58    pub manga_id: Uuid,
59
60    #[builder(setter(each = "include"), default)]
61    pub includes: Vec<ReferenceExpansionResource>,
62}
63
64endpoint! {
65    GET ("/manga/{}/relation", manga_id),
66    #[query] ListMangaRelations,
67    #[flatten_result] MangaRelationListResponse,
68    ListMangaRelationsBuilder
69}
70
71#[cfg(test)]
72mod tests {
73    use serde_json::json;
74    use url::Url;
75    use uuid::Uuid;
76    use wiremock::matchers::{method, path_regex};
77    use wiremock::{Mock, MockServer, ResponseTemplate};
78
79    use crate::{HttpClient, MangaDexClient};
80    use mangadex_api_types::{MangaRelation, RelationshipType, ResponseType};
81
82    #[tokio::test]
83    async fn get_manga_fires_a_request_to_base_url() -> anyhow::Result<()> {
84        let mock_server = MockServer::start().await;
85        let http_client = HttpClient::builder()
86            .base_url(Url::parse(&mock_server.uri())?)
87            .build()?;
88        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
89
90        let manga_id = Uuid::new_v4();
91        let response_body = json!({
92            "result": "ok",
93            "response": "collection",
94            "data": [
95                {
96                    "id": "0b92f446-4ee0-4c15-9e5c-6ae1211e785b",
97                    "type": "manga_relation",
98                    "attributes": {
99                        "relation": "doujinshi",
100                        "version": 1
101                    },
102                    "relationships": [
103                        {
104                            "id": "7944cc53-86e6-4135-898f-47c5c8d0647c",
105                            "type": "manga"
106                        }
107                    ]
108                },
109                {
110                    "id": "31b831b7-aac5-4797-b3eb-a41575cd4399",
111                    "type": "manga_relation",
112                    "attributes": {
113                        "relation": "doujinshi",
114                        "version": 1
115                    },
116                    "relationships": [
117                        {
118                            "id": "119327ab-9b32-4841-9068-02264c15e118",
119                            "type": "manga"
120                        }
121                    ]
122                },
123                {
124                    "id": "53815c02-b357-4e23-b8e7-0d6d114ea420",
125                    "type": "manga_relation",
126                    "attributes": {
127                        "relation": "doujinshi",
128                        "version": 1
129                    },
130                    "relationships": [
131                        {
132                            "id": "25e26436-7eb7-4505-8711-6e014bb16fd7",
133                            "type": "manga"
134                        }
135                    ]
136                },
137                {
138                    "id": "6958767b-54c5-4b4c-8f0f-579a36389f68",
139                    "type": "manga_relation",
140                    "attributes": {
141                        "relation": "doujinshi",
142                        "version": 1
143                    },
144                    "relationships": [
145                        {
146                            "id": "0736a46a-1a34-4411-b665-a1e45ebf54a9",
147                            "type": "manga"
148                        }
149                    ]
150                },
151                {
152                    "id": "b358b2f5-beab-484a-9daf-880ad6085225",
153                    "type": "manga_relation",
154                    "attributes": {
155                        "relation": "spin_off",
156                        "version": 1
157                    },
158                    "relationships": [
159                        {
160                            "id": "1e4deefe-9eb8-4183-837a-f24002adb318",
161                            "type": "manga"
162                        }
163                    ]
164                }
165            ],
166            "limit": 5,
167            "offset": 0,
168            "total": 5
169        });
170
171        Mock::given(method("GET"))
172            .and(path_regex(r"/manga/[0-9a-fA-F-]+/relation"))
173            .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
174            .expect(1)
175            .mount(&mock_server)
176            .await;
177
178        let res = mangadex_client
179            .manga()
180            .manga_id(manga_id)
181            .relation()
182            .get()
183            .send()
184            .await?;
185
186        let related = &res.data[0];
187        assert_eq!(res.response, ResponseType::Collection);
188        assert_eq!(related.type_, RelationshipType::MangaRelation);
189        assert_eq!(related.attributes.relation, MangaRelation::Doujinshi);
190        assert_eq!(related.attributes.version, 1);
191        assert_eq!(related.relationships[0].type_, RelationshipType::Manga);
192        assert!(related.relationships[0].related.is_none());
193        assert!(related.relationships[0].attributes.is_none());
194
195        Ok(())
196    }
197}