vndb_api/
client.rs

1use reqwest::Client;
2
3use crate::format::error::VndbApiError;
4use crate::request::query::{
5    CharacterQuery, ProducerQuery, Query, ReleaseQuery, StaffQuery, TagQuery, TraitQuery,
6    UListQuery, VnQuery,
7};
8use crate::request::response::Response;
9
10use crate::format::auth::AuthInfo;
11use crate::format::stats::VndbStats;
12use crate::format::user::{UserSearch, UserSearchFields};
13
14use crate::format::character::Character;
15use crate::format::producer::Producer;
16use crate::format::release::Release;
17use crate::format::rlist::RListPatch;
18use crate::format::staff::Staff;
19use crate::format::tag::Tag;
20use crate::format::traits::Trait;
21use crate::format::ulist::{UList, UListLabels, UListLabelsFieldChoices, UListPatch};
22use crate::format::vn::VisualNovel;
23
24const API_ENDPOINT: &str = "https://api.vndb.org/kana";
25
26pub struct VndbApiClient {
27    client: Client,
28    access_token: String,
29}
30
31impl VndbApiClient {
32    pub fn new(token: &String) -> Self {
33        VndbApiClient {
34            client: Client::new(),
35            access_token: token.clone(),
36        }
37    }
38
39    pub async fn get_stats(&self) -> Result<VndbStats, VndbApiError> {
40        let url = format!("{}/stats", API_ENDPOINT);
41        let response = self.client.get(&url).send().await?;
42
43        if response.status().is_success() {
44            let result = response.json::<VndbStats>().await?;
45            Ok(result)
46        } else {
47            Err(VndbApiError::new(response.status(), response.text().await?))
48        }
49    }
50
51    pub async fn get_auth_info(&self) -> Result<AuthInfo, VndbApiError> {
52        let url = format!("{}/authinfo", API_ENDPOINT);
53        let response = self
54            .client
55            .get(&url)
56            .header("Authorization", format!("token {}", self.access_token))
57            .send()
58            .await?;
59
60        if response.status().is_success() {
61            let result = response.json::<AuthInfo>().await?;
62            Ok(result)
63        } else {
64            Err(VndbApiError::new(response.status(), response.text().await?))
65        }
66    }
67
68    pub async fn get_user(
69        &self,
70        q: &Vec<String>,
71        fields: &UserSearchFields,
72    ) -> Result<UserSearch, VndbApiError> {
73        let url = format!(
74            "{}/user?q={}&fields={}",
75            API_ENDPOINT,
76            q.join("&q="),
77            fields.to_csv()
78        );
79        let response = self.client.get(&url).json(q).send().await?;
80
81        if response.status().is_success() {
82            let result = response.json::<UserSearch>().await?;
83            Ok(result)
84        } else {
85            Err(VndbApiError::new(response.status(), response.text().await?))
86        }
87    }
88
89    pub async fn vn_search(
90        &self,
91        q: &Query<VnQuery>,
92    ) -> Result<Response<VisualNovel>, VndbApiError> {
93        let url = format!("{}/vn", API_ENDPOINT);
94        let response = self.client.post(&url).json(q).send().await?;
95
96        if response.status().is_success() {
97            let result = response.json::<Response<VisualNovel>>().await?;
98            Ok(result)
99        } else {
100            Err(VndbApiError::new(response.status(), response.text().await?))
101        }
102    }
103
104    pub async fn release_search(
105        &self,
106        q: &Query<ReleaseQuery>,
107    ) -> Result<Response<Release>, VndbApiError> {
108        let url = format!("{}/release", API_ENDPOINT);
109        let response = self.client.post(&url).json(q).send().await?;
110
111        if response.status().is_success() {
112            let result = response.json::<Response<Release>>().await?;
113            Ok(result)
114        } else {
115            Err(VndbApiError::new(response.status(), response.text().await?))
116        }
117    }
118
119    pub async fn producer_search(
120        &self,
121        q: &Query<ProducerQuery>,
122    ) -> Result<Response<Producer>, VndbApiError> {
123        let url = format!("{}/producer", API_ENDPOINT);
124        let response = self.client.post(&url).json(q).send().await?;
125
126        if response.status().is_success() {
127            let result = response.json::<Response<Producer>>().await?;
128            Ok(result)
129        } else {
130            Err(VndbApiError::new(response.status(), response.text().await?))
131        }
132    }
133
134    pub async fn character_search(
135        &self,
136        q: &Query<CharacterQuery>,
137    ) -> Result<Response<Character>, VndbApiError> {
138        let url = format!("{}/character", API_ENDPOINT);
139        let response = self.client.post(&url).json(q).send().await?;
140
141        if response.status().is_success() {
142            let result = response.json::<Response<Character>>().await?;
143            Ok(result)
144        } else {
145            Err(VndbApiError::new(response.status(), response.text().await?))
146        }
147    }
148
149    pub async fn staff_search(
150        &self,
151        q: &Query<StaffQuery>,
152    ) -> Result<Response<Staff>, VndbApiError> {
153        let url = format!("{}/staff", API_ENDPOINT);
154        let response = self.client.post(&url).json(q).send().await?;
155
156        if response.status().is_success() {
157            let result = response.json::<Response<Staff>>().await?;
158            Ok(result)
159        } else {
160            Err(VndbApiError::new(response.status(), response.text().await?))
161        }
162    }
163
164    pub async fn tag_search(&self, q: &Query<TagQuery>) -> Result<Response<Tag>, VndbApiError> {
165        let url = format!("{}/tag", API_ENDPOINT);
166        let response = self.client.post(&url).json(q).send().await?;
167
168        if response.status().is_success() {
169            let result = response.json::<Response<Tag>>().await?;
170            Ok(result)
171        } else {
172            Err(VndbApiError::new(response.status(), response.text().await?))
173        }
174    }
175
176    pub async fn trait_search(
177        &self,
178        q: &Query<TraitQuery>,
179    ) -> Result<Response<Trait>, VndbApiError> {
180        let url = format!("{}/trait", API_ENDPOINT);
181        let response = self.client.post(&url).json(q).send().await?;
182
183        if response.status().is_success() {
184            let result = response.json::<Response<Trait>>().await?;
185            Ok(result)
186        } else {
187            Err(VndbApiError::new(response.status(), response.text().await?))
188        }
189    }
190
191    pub async fn ulist(&self, q: &Query<UListQuery>) -> Result<Response<UList>, VndbApiError> {
192        let url = format!("{}/ulist", API_ENDPOINT);
193        let response = self.client.post(&url).json(q).send().await?;
194
195        if response.status().is_success() {
196            let result = response.json::<Response<UList>>().await?;
197            Ok(result)
198        } else {
199            Err(VndbApiError::new(response.status(), response.text().await?))
200        }
201    }
202
203    pub async fn get_ulist_labels(
204        &self,
205        user: &String,
206        fields: &UListLabelsFieldChoices,
207    ) -> Result<UListLabels, VndbApiError> {
208        let url = format!(
209            "{}/ulist_labels?user={}&fields={}",
210            API_ENDPOINT,
211            user.clone(),
212            fields.to_csv()
213        );
214        let response = self.client.get(&url).send().await?;
215
216        if response.status().is_success() {
217            let result = response.json::<UListLabels>().await?;
218            Ok(result)
219        } else {
220            Err(VndbApiError::new(response.status(), response.text().await?))
221        }
222    }
223
224    pub async fn ulist_patch(
225        &self,
226        vn_id: &String,
227        patch: &UListPatch,
228    ) -> Result<(), VndbApiError> {
229        let url = format!("{}/ulist/{}", API_ENDPOINT, vn_id);
230        let response = self
231            .client
232            .patch(&url)
233            .header("Authorization", format!("token {}", self.access_token))
234            .header("Content-Type", "application/json")
235            .json(patch)
236            .send()
237            .await?;
238
239        if response.status().is_success() {
240            Ok(())
241        } else {
242            Err(VndbApiError::new(response.status(), response.text().await?))
243        }
244    }
245
246    pub async fn rlist_patch(&self, r_id: &String, patch: &RListPatch) -> Result<(), VndbApiError> {
247        let url = format!("{}/rlist/{}", API_ENDPOINT, r_id);
248        let response = self
249            .client
250            .patch(&url)
251            .header("Authorization", format!("token {}", self.access_token))
252            .header("Content-Type", "application/json")
253            .json(patch)
254            .send()
255            .await?;
256
257        if response.status().is_success() {
258            Ok(())
259        } else {
260            Err(VndbApiError::new(response.status(), response.text().await?))
261        }
262    }
263
264    pub async fn ulist_remove(&self, vn_id: &String) -> Result<(), VndbApiError> {
265        let url = format!("{}/ulist/{}", API_ENDPOINT, vn_id);
266        let response = self
267            .client
268            .delete(&url)
269            .header("Authorization", format!("token {}", self.access_token))
270            .send()
271            .await?;
272
273        if response.status().is_success() {
274            Ok(())
275        } else {
276            Err(VndbApiError::new(response.status(), response.text().await?))
277        }
278    }
279
280    pub async fn rlist_remove(&self, r_id: &String) -> Result<(), VndbApiError> {
281        let url = format!("{}/rlist/{}", API_ENDPOINT, r_id);
282        let response = self
283            .client
284            .delete(&url)
285            .header("Authorization", format!("token {}", self.access_token))
286            .send()
287            .await?;
288
289        if response.status().is_success() {
290            Ok(())
291        } else {
292            Err(VndbApiError::new(response.status(), response.text().await?))
293        }
294    }
295}