mangadex_api/v5/manga/manga_id/relation/id/
delete.rs1use derive_builder::Builder;
51use serde::Serialize;
52use uuid::Uuid;
53
54use crate::HttpClientRef;
55use mangadex_api_schema::NoData;
56use mangadex_api_types::error::Result;
57
58#[cfg_attr(
59 feature = "deserializable-endpoint",
60 derive(serde::Deserialize, getset::Getters, getset::Setters)
61)]
62#[derive(Debug, Serialize, Clone, Builder, Default)]
63#[serde(rename_all = "camelCase")]
64#[builder(
65 setter(into),
66 build_fn(error = "mangadex_api_types::error::BuilderError")
67)]
68pub struct DeleteMangaRelation {
69 #[doc(hidden)]
71 #[serde(skip)]
72 #[builder(pattern = "immutable")]
73 #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
74 pub http_client: HttpClientRef,
75
76 #[serde(skip_serializing)]
77 pub manga_id: Uuid,
78 #[serde(skip_serializing)]
79 pub relation_id: Uuid,
80}
81
82endpoint! {
83 DELETE ("/manga/{}/relation/{}", manga_id, relation_id),
84 #[no_data auth] DeleteMangaRelation,
85 #[discard_result] Result<NoData>,
86 DeleteMangaRelationBuilder
87}
88
89#[cfg(test)]
90mod tests {
91 use serde_json::json;
92 use url::Url;
93 use uuid::Uuid;
94 use wiremock::matchers::{header, method, path_regex};
95 use wiremock::{Mock, MockServer, ResponseTemplate};
96
97 use crate::v5::AuthTokens;
98 use crate::{HttpClient, MangaDexClient};
99 use mangadex_api_types::error::Error;
100
101 #[tokio::test]
102 async fn delete_manga_relation_fires_a_request_to_base_url() -> anyhow::Result<()> {
103 let mock_server = MockServer::start().await;
104 let http_client = HttpClient::builder()
105 .base_url(Url::parse(&mock_server.uri())?)
106 .auth_tokens(AuthTokens {
107 session: "sessiontoken".to_string(),
108 refresh: "refreshtoken".to_string(),
109 })
110 .build()?;
111 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
112
113 let manga_id = Uuid::new_v4();
114 let relation_id = Uuid::new_v4();
115 let response_body = json!({
116 "result": "ok",
117 });
118
119 Mock::given(method("DELETE"))
120 .and(path_regex(r"/manga/[0-9a-fA-F-]+/relation/[0-9a-fA-F-]+"))
121 .and(header("Authorization", "Bearer sessiontoken"))
122 .respond_with(ResponseTemplate::new(200).set_body_json(response_body))
123 .expect(1)
124 .mount(&mock_server)
125 .await;
126
127 let res = mangadex_client
128 .manga()
129 .manga_id(manga_id)
130 .relation()
131 .id(relation_id)
132 .delete()
133 .send()
134 .await;
135
136 assert!(res.is_ok());
137
138 Ok(())
139 }
140
141 #[tokio::test]
142 async fn delete_manga_relation_requires_auth() -> anyhow::Result<()> {
143 let mock_server = MockServer::start().await;
144 let http_client: HttpClient = HttpClient::builder()
145 .base_url(Url::parse(&mock_server.uri())?)
146 .build()?;
147 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
148
149 let manga_id = Uuid::new_v4();
150 let relation_id = Uuid::new_v4();
151 let error_id = Uuid::new_v4();
152 let response_body = json!({
153 "result": "error",
154 "errors": [{
155 "id": error_id.to_string(),
156 "status": 403,
157 "title": "Forbidden",
158 "detail": "You must be logged in to continue."
159 }]
160 });
161
162 Mock::given(method("DELETE"))
163 .and(path_regex(r"/manga/[0-9a-fA-F-]+/relation/[0-9a-fA-F-]+"))
164 .respond_with(ResponseTemplate::new(403).set_body_json(response_body))
165 .expect(0)
166 .mount(&mock_server)
167 .await;
168
169 let res = mangadex_client
170 .manga()
171 .manga_id(manga_id)
172 .relation()
173 .id(relation_id)
174 .delete()
175 .send()
176 .await
177 .expect_err("expected error");
178
179 match res {
180 Error::MissingTokens => {}
181 _ => panic!("unexpected error: {:#?}", res),
182 }
183
184 Ok(())
185 }
186}