mangadex_api/v5/api_client/id/
post.rs

1//! Builder for editing client by its id.
2//!
3//! <https://api.mangadex.org/docs/swagger.html#/ApiClient/post-edit-apiclient>
4//!
5//! # Examples
6//!
7//! ```rust
8//! use mangadex_api::v5::MangaDexClient;
9//! use uuid::Uuid;
10//!
11//! # async fn run() -> anyhow::Result<()> {
12//! let client = MangaDexClient::default();
13//!
14//! let client_res = client
15//!     .client()
16//!     .id(Uuid::new_v4())
17//!     .post()
18//!     .description("My API for testing")
19//!     // Normally you don't need this `as u32`
20//!     // but for some reason, it need this to compile :(
21//!     .version(2 as u32)
22//!     .send()
23//!     .await?;
24//!
25//! println!("client: {:?}", client_res);
26//! # Ok(())
27//! # }
28//! ```
29//!
30use derive_builder::Builder;
31use serde::Serialize;
32
33use crate::HttpClientRef;
34use mangadex_api_schema::v5::ApiClientResponse;
35use uuid::Uuid;
36
37/// Create a new api client.
38///
39/// This requires authentication.
40///
41/// Makes a request to `POST /client`
42#[cfg_attr(
43    feature = "deserializable-endpoint",
44    derive(serde::Deserialize, getset::Getters, getset::Setters)
45)]
46#[derive(Debug, Serialize, Clone, Builder, Default)]
47#[serde(rename_all = "camelCase")]
48#[builder(
49    setter(into, strip_option),
50    build_fn(error = "mangadex_api_types::error::BuilderError")
51)]
52#[cfg_attr(feature = "non_exhaustive", non_exhaustive)]
53pub struct EditClient {
54    /// This should never be set manually as this is only for internal use.
55    #[doc(hidden)]
56    #[serde(skip)]
57    #[builder(pattern = "immutable")]
58    #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
59    pub http_client: HttpClientRef,
60
61    #[serde(skip_serializing)]
62    pub client_id: Uuid,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    #[builder(default)]
65    pub description: Option<String>,
66    // >= 1
67    pub version: u32,
68}
69
70endpoint! {
71    POST ("/client/{}", client_id),
72    #[body auth] EditClient,
73    #[flatten_result] ApiClientResponse,
74    EditClientBuilder
75}
76
77#[cfg(test)]
78mod tests {
79    use serde::Serialize;
80    use serde_json::json;
81    use url::Url;
82    use uuid::Uuid;
83    use wiremock::matchers::{body_json, header, method, path_regex};
84    use wiremock::{Mock, MockServer, ResponseTemplate};
85
86    use crate::{HttpClient, MangaDexClient};
87    use mangadex_api_schema::v5::AuthTokens;
88    use mangadex_api_types::RelationshipType;
89
90    #[derive(Serialize, Clone)]
91    struct EditClientBody {
92        description: Option<String>,
93        version: u32,
94    }
95
96    #[tokio::test]
97    async fn edit_client_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: "myToken".to_string(),
103                refresh: "myRefreshToken".to_string(),
104            })
105            .build()?;
106        let mangadex_client = MangaDexClient::new_with_http_client(http_client);
107
108        let client_id = Uuid::parse_str("eec486de-24f0-4e68-8459-34f26a62ceaa").unwrap();
109
110        let _expected_body: EditClientBody = EditClientBody{
111            description: Some("This is a API Client used for the [mangadex-api](https://github.com/tonymushah/mangadex-api) tests.".to_string()),
112            version: 1
113        };
114
115        let response_body = json!({
116          "result": "ok",
117          "response": "entity",
118          "data": {
119            "id": client_id,
120            "type": "api_client",
121            "attributes": {
122              "name": "Mangadex-API-Auth",
123              "description": _expected_body.description.clone(),
124              "profile": "personal",
125              "externalClientId": null,
126              "isActive": false,
127              "state": "requested",
128              "createdAt": "2023-10-28T12:37:22+00:00",
129              "updatedAt": "2023-10-28T12:37:22+00:00",
130              "version": _expected_body.version
131            },
132            "relationships": [
133              {
134                "id": "554149c7-f28f-4a30-b5fa-9db9b1e11353",
135                "type": "creator"
136              }
137            ]
138          }
139        });
140
141        Mock::given(method("POST"))
142            .and(path_regex(r"/client/[0-9a-fA-F-]+"))
143            .and(header("Authorization", "Bearer myToken"))
144            .and(header("Content-Type", "application/json"))
145            .and(body_json(_expected_body.clone()))
146            .respond_with(ResponseTemplate::new(201).set_body_json(response_body))
147            .expect(1)
148            .mount(&mock_server)
149            .await;
150
151        let res = mangadex_client
152            .client()
153            .id(client_id)
154            .post()
155            .description(_expected_body.description.clone().unwrap())
156            .version(_expected_body.version)
157            .send()
158            .await?;
159
160        assert_eq!(res.data.type_, RelationshipType::ApiClient);
161        assert_eq!(
162            res.data.attributes.description,
163            _expected_body.description.clone()
164        );
165        assert_eq!(res.data.attributes.version, _expected_body.version);
166        Ok(())
167    }
168}