mangadex_api/v5/custom_list/id/follow/
post.rs

1//! Builder for the follow CustomList endpoint.
2//!
3//! <https://api.mangadex.org/swagger.html#/CustomList/follow-list-id>
4//!
5//! # Examples
6//!
7//! ```rust
8//! use uuid::Uuid;
9//!
10//! use mangadex_api::v5::MangaDexClient;
11//! // use mangadex_api_types::{Password, Username};
12//!
13//! # async fn run() -> anyhow::Result<()> {
14//! let client = MangaDexClient::default();
15//!
16//! /*
17//! let _login_res = client
18//!     .auth()
19//!     .login()
20//!     .username(Username::parse("myusername")?)
21//!     .password(Password::parse("hunter23")?)
22//!     .build()?
23//!     .send()
24//!     .await?;
25//! */
26//!
27//! let list_id = Uuid::new_v4();
28//! let _ = client
29//!     .custom_list()
30//!     .id(list_id)
31//!     .follow()
32//!     .post()
33//!     .send()
34//!     .await?;
35//!
36//! # Ok(())
37//! # }
38//! ```
39
40use derive_builder::Builder;
41use mangadex_api_schema::NoData;
42use serde::Serialize;
43use uuid::Uuid;
44
45use crate::HttpClientRef;
46use mangadex_api_types::error::Result;
47
48#[cfg_attr(
49    feature = "deserializable-endpoint",
50    derive(serde::Deserialize, getset::Getters, getset::Setters)
51)]
52#[derive(Debug, Serialize, Clone, Builder)]
53#[serde(rename_all = "camelCase")]
54#[builder(
55    setter(into, strip_option),
56    build_fn(error = "mangadex_api_types::error::BuilderError")
57)]
58#[cfg_attr(feature = "non_exhaustive", non_exhaustive)]
59pub struct FollowCustomList {
60    /// This should never be set manually as this is only for internal use.
61    #[doc(hidden)]
62    #[serde(skip)]
63    #[builder(pattern = "immutable")]
64    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
65    pub http_client: HttpClientRef,
66
67    /// CustomList ID.
68    #[serde(skip_serializing)]
69    pub list_id: Uuid,
70}
71
72endpoint! {
73    POST ("/list/{}/follow", list_id),
74    #[body auth] FollowCustomList,
75    #[discard_result] Result<NoData>,
76    FollowCustomListBuilder
77}
78
79#[cfg(test)]
80mod tests {
81    use serde_json::json;
82    use url::Url;
83    use uuid::Uuid;
84    use wiremock::matchers::{header, method, path_regex};
85    use wiremock::{Mock, MockServer, ResponseTemplate};
86
87    use crate::v5::AuthTokens;
88    use crate::{HttpClient, MangaDexClient};
89
90    #[tokio::test]
91    async fn follow_custom_list_fires_a_request_to_base_url() -> anyhow::Result<()> {
92        let mock_server = MockServer::start().await;
93        let http_client = HttpClient::builder()
94            .base_url(Url::parse(&mock_server.uri())?)
95            .auth_tokens(AuthTokens {
96                session: "sessiontoken".to_string(),
97                refresh: "refreshtoken".to_string(),
98            })
99            .build()?;
100        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
101
102        let custom_list_id = Uuid::new_v4();
103        let response_body = json!({
104            "result": "ok"
105        });
106
107        Mock::given(method("POST"))
108            .and(path_regex(r"/list/[0-9a-fA-F-]+/follow"))
109            .and(header("Authorization", "Bearer sessiontoken"))
110            .and(header("Content-Type", "application/json"))
111            .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
112            .expect(1)
113            .mount(&mock_server)
114            .await;
115
116        mangadex_client
117            .custom_list()
118            .id(custom_list_id)
119            .follow()
120            .post()
121            .send()
122            .await?;
123
124        Ok(())
125    }
126}