mangadex_api/v5/rating/manga_id/
delete.rs

1//! Builder for the delete Manga rating endpoint.
2//!
3//! This endpoint requires authentication.
4//!
5//! <https://api.mangadex.org/docs/swagger.html#/Rating/delete-rating-manga-id>
6//!
7//! # Examples
8//!
9//! ```rust
10//! use uuid::Uuid;
11//!
12//! // use mangadex_api_types::{Password, Username};
13//! use mangadex_api::v5::MangaDexClient;
14//!
15//! # async fn run() -> anyhow::Result<()> {
16//! let client = MangaDexClient::default();
17//!
18//! /*
19//!
20//!     let _login_res = client
21//!         .auth()
22//!         .login()
23//!         .get()
24//!         .username(Username::parse("myusername")?)
25//!         .password(Password::parse("hunter23")?)
26//!         .send()
27//!         .await?;
28//!
29//!  */
30//!
31//!
32//! // Official Test Manga ID.
33//! let manga_id = Uuid::parse_str("f9c33607-9180-4ba6-b85c-e4b5faee7192")?;
34//!
35//! let res = client
36//!     .rating()
37//!     .manga_id(manga_id)
38//!     .delete()
39//!     .send()
40//!     .await?;
41//!
42//! println!("Response: {:?}", res);
43//! # Ok(())
44//! # }
45//! ```
46
47use derive_builder::Builder;
48use serde::Serialize;
49use uuid::Uuid;
50
51use crate::HttpClientRef;
52use mangadex_api_schema::NoData;
53use mangadex_api_types::error::Result;
54
55#[cfg_attr(
56    feature = "deserializable-endpoint",
57    derive(serde::Deserialize, getset::Getters, getset::Setters)
58)]
59#[derive(Debug, Serialize, Clone, Builder)]
60#[serde(rename_all = "camelCase")]
61#[builder(
62    setter(into, strip_option),
63    build_fn(error = "mangadex_api_types::error::BuilderError")
64)]
65pub struct DeleteMangaRating {
66    /// This should never be set manually as this is only for internal use.
67    #[doc(hidden)]
68    #[serde(skip)]
69    #[builder(pattern = "immutable")]
70    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
71    pub http_client: HttpClientRef,
72
73    #[serde(skip_serializing)]
74    pub manga_id: Uuid,
75}
76
77endpoint! {
78    DELETE ("/rating/{}", manga_id),
79    #[no_data auth] DeleteMangaRating,
80    #[discard_result] Result<NoData>,
81    DeleteMangaRatingBuilder
82}
83
84#[cfg(test)]
85mod tests {
86    use serde_json::json;
87    use url::Url;
88    use uuid::Uuid;
89    use wiremock::matchers::{header, method, path_regex};
90    use wiremock::{Mock, MockServer, ResponseTemplate};
91
92    use crate::v5::AuthTokens;
93    use crate::{HttpClient, MangaDexClient};
94    use mangadex_api_types::error::Error;
95
96    #[tokio::test]
97    async fn delete_manga_rating_fires_a_request_to_base_url() -> anyhow::Result<()> {
98        let mock_server = MockServer::start().await;
99        let http_client = HttpClient::builder()
100            .base_url(Url::parse(&mock_server.uri())?)
101            .auth_tokens(AuthTokens {
102                session: "sessiontoken".to_string(),
103                refresh: "refreshtoken".to_string(),
104            })
105            .build()?;
106        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
107
108        let manga_id = Uuid::new_v4();
109        let response_body = json!({
110            "result": "ok",
111        });
112
113        Mock::given(method("DELETE"))
114            .and(path_regex(r"/rating/[0-9a-fA-F-]+"))
115            .and(header("Authorization", "Bearer sessiontoken"))
116            .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
117            .expect(1)
118            .mount(&mock_server)
119            .await;
120
121        mangadex_client
122            .rating()
123            .manga_id(manga_id)
124            .delete()
125            .send()
126            .await?;
127
128        Ok(())
129    }
130
131    #[tokio::test]
132    async fn delete_manga_rating_requires_auth() -> anyhow::Result<()> {
133        let mock_server = MockServer::start().await;
134        let http_client: HttpClient = HttpClient::builder()
135            .base_url(Url::parse(&mock_server.uri())?)
136            .build()?;
137        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
138
139        let manga_id = Uuid::new_v4();
140        let error_id = Uuid::new_v4();
141        let response_body = json!({
142            "result": "error",
143            "errors": [{
144                "id": error_id.to_string(),
145                "status": 403,
146                "title": "Forbidden",
147                "detail": "You must be logged in to continue."
148            }]
149        });
150
151        Mock::given(method("DELETE"))
152            .and(path_regex(r"/rating/[0-9a-fA-F-]+/relation"))
153            .and(header("Content-Type", "application/json"))
154            .respond_with(ResponseTemplate::new(403).set_body_json(response_body))
155            .expect(0)
156            .mount(&mock_server)
157            .await;
158
159        let res = mangadex_client
160            .rating()
161            .manga_id(manga_id)
162            .delete()
163            .send()
164            .await
165            .expect_err("expected error");
166
167        match res {
168            Error::MissingTokens => {}
169            _ => panic!("unexpected error: {:#?}", res),
170        }
171
172        Ok(())
173    }
174}