mangadex_api/v5/api_client/
post.rs1use derive_builder::Builder;
43use serde::Serialize;
44
45use crate::HttpClientRef;
46use mangadex_api_types::ApiClientProfile;
47
48type ApiClientResponse = crate::Result<mangadex_api_schema::v5::ApiClientData>;
49
50#[cfg_attr(
56 feature = "deserializable-endpoint",
57 derive(serde::Deserialize, getset::Getters, getset::Setters)
58)]
59#[derive(Debug, Serialize, Clone, Builder, Default)]
60#[serde(rename_all = "camelCase")]
61#[builder(
62 setter(into, strip_option),
63 build_fn(error = "crate::error::BuilderError")
64)]
65#[non_exhaustive]
66pub struct CreateClient {
67 #[doc(hidden)]
69 #[serde(skip)]
70 #[builder(pattern = "immutable")]
71 #[cfg_attr(feature = "deserializable-endpoint", getset(set = "pub", get = "pub"))]
72 pub http_client: HttpClientRef,
73
74 pub name: String,
75 #[serde(skip_serializing_if = "Option::is_none")]
76 #[builder(default)]
77 pub description: Option<String>,
78 #[builder(default)]
79 pub profile: ApiClientProfile,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 #[builder(default = "Some(1)")]
82 pub version: Option<u32>,
83}
84
85endpoint! {
86 POST "/client",
87 #[body auth] CreateClient,
88 #[flatten_result] ApiClientResponse,
89 CreateClientBuilder
90}
91
92#[cfg(test)]
93mod tests {
94 use serde_json::json;
95 use time::OffsetDateTime;
96 use url::Url;
97 use uuid::Uuid;
98 use wiremock::matchers::{body_json, header, method, path};
99 use wiremock::{Mock, MockServer, ResponseTemplate};
100
101 use crate::v5::AuthTokens;
102 use crate::{HttpClient, MangaDexClient};
103 use mangadex_api_types::{ApiClientProfile, ApiClientState, MangaDexDateTime};
104 use serde::Serialize;
105
106 #[derive(Serialize, Clone)]
107 struct CreateClientTestBody {
108 pub name: String,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub description: Option<String>,
111 #[serde(default)]
112 pub profile: ApiClientProfile,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub version: Option<u32>,
115 }
116
117 #[tokio::test]
118 async fn create_client_fires_a_request_to_base_url() -> anyhow::Result<()> {
119 let mock_server = MockServer::start().await;
120 let http_client: HttpClient = HttpClient::builder()
121 .base_url(Url::parse(&mock_server.uri())?)
122 .auth_tokens(non_exhaustive::non_exhaustive!(AuthTokens {
123 session: "sessiontoken".to_string(),
124 refresh: "refreshtoken".to_string(),
125 }))
126 .build()?;
127 let mangadex_client = MangaDexClient::new_with_http_client(http_client);
128
129 let client_id = Uuid::new_v4();
130 let datetime = MangaDexDateTime::new(&OffsetDateTime::now_utc());
131
132 let _expected_body = CreateClientTestBody {
133 name: "mangadex-api".to_string(),
134 description: Some("a test api for the mangadex-api".to_string()),
135 profile: ApiClientProfile::Personal,
136 version: Some(1),
137 };
138 let state = ApiClientState::Requested;
139 let response_body = json!({
140 "result": "ok",
141 "response": "entity",
142 "data": {
143 "id": client_id,
144 "type": "api_client",
145 "attributes": {
146 "name": _expected_body.name,
147 "description": _expected_body.description,
148 "profile": _expected_body.profile,
149 "externalClientId": null,
150 "isActive": false,
151 "state": state,
152 "createdAt": datetime.to_string(),
153 "updatedAt": datetime.to_string(),
154 "version": 1
155 },
156 "relationships": []
157 }
158 });
159 Mock::given(method("POST"))
160 .and(path("/client"))
161 .and(header("Authorization", "Bearer sessiontoken"))
162 .and(header("Content-Type", "application/json"))
163 .and(body_json(_expected_body.clone()))
164 .respond_with(ResponseTemplate::new(201).set_body_json(response_body))
165 .expect(1)
166 .mount(&mock_server)
167 .await;
168
169 let mut req_binding = mangadex_client.client().post();
170 let req = req_binding.name(_expected_body.name.clone());
171 if let Some(description) = _expected_body.description.clone() {
172 req.description(description);
173 }
174 req.profile(_expected_body.profile);
175 if let Some(version) = _expected_body.version {
176 req.version(version);
177 }
178
179 let res = req.send().await?;
180 let data = res.data;
181 assert_eq!(data.id, client_id);
182 assert_eq!(data.attributes.name, _expected_body.name);
183 assert_eq!(data.attributes.description, _expected_body.description);
184 assert!(data.attributes.external_client_id.is_none());
185 assert!(!data.attributes.is_active);
186 assert_eq!(data.attributes.state, state);
187 assert_eq!(data.attributes.created_at.to_string(), datetime.to_string());
188 assert_eq!(data.attributes.updated_at.to_string(), datetime.to_string());
189 assert_eq!(data.attributes.profile, _expected_body.profile);
190 Ok(())
191 }
192}