1use edda_types::{
5 monster::{Monster, MonsterSheet, MonsterSummary},
6 rules_text::{Entry, RulesText},
7};
8use uuid::Uuid;
9
10use crate::{ClientError, check, http_client, send};
11
12#[derive(Debug, Clone)]
14pub struct MonsterClient {
15 base_url: String,
16 http: reqwest::Client,
17}
18
19impl MonsterClient {
20 pub fn new(base_url: impl Into<String>) -> Self {
22 Self {
23 base_url: base_url.into().trim_end_matches('/').to_string(),
24 http: http_client(None),
25 }
26 }
27
28 #[must_use]
31 pub fn with_token(mut self, token: &str) -> Self {
32 self.http = http_client(Some(token));
33 self
34 }
35
36 pub async fn list(&self, search: Option<&str>) -> Result<Vec<MonsterSummary>, ClientError> {
39 let mut request = self.http.get(self.url("/monsters"));
40 if let Some(search) = search {
41 request = request.query(&[("search", search)]);
42 }
43 send(request).await
44 }
45
46 pub async fn get(&self, id: Uuid) -> Result<Monster, ClientError> {
48 send(self.http.get(self.monster_url(id))).await
49 }
50
51 pub async fn create(&self, sheet: &MonsterSheet) -> Result<Monster, ClientError> {
53 send(self.http.post(self.url("/monsters")).json(sheet)).await
54 }
55
56 pub async fn replace(&self, id: Uuid, sheet: &MonsterSheet) -> Result<Monster, ClientError> {
59 send(self.http.put(self.monster_url(id)).json(sheet)).await
60 }
61
62 pub async fn delete(&self, id: Uuid) -> Result<(), ClientError> {
64 let response = self.http.delete(self.monster_url(id)).send().await?;
65 check(response).await.map(drop)
66 }
67
68 pub async fn texts<T: RulesText>(
72 &self,
73 search: Option<&str>,
74 ) -> Result<Vec<Entry<T>>, ClientError> {
75 let mut request = self.http.get(self.url(&format!("/{}", T::KIND)));
76 if let Some(search) = search {
77 request = request.query(&[("search", search)]);
78 }
79 send(request).await
80 }
81
82 pub async fn text<T: RulesText>(&self, id: Uuid) -> Result<Entry<T>, ClientError> {
84 send(self.http.get(self.text_url::<T>(id))).await
85 }
86
87 pub async fn create_text<T: RulesText>(&self, text: &T) -> Result<Entry<T>, ClientError> {
89 send(
90 self.http
91 .post(self.url(&format!("/{}", T::KIND)))
92 .json(text),
93 )
94 .await
95 }
96
97 pub async fn replace_text<T: RulesText>(
100 &self,
101 id: Uuid,
102 text: &T,
103 ) -> Result<Entry<T>, ClientError> {
104 send(self.http.put(self.text_url::<T>(id)).json(text)).await
105 }
106
107 pub async fn delete_text<T: RulesText>(&self, id: Uuid) -> Result<(), ClientError> {
109 let response = self.http.delete(self.text_url::<T>(id)).send().await?;
110 check(response).await.map(drop)
111 }
112
113 fn text_url<T: RulesText>(&self, id: Uuid) -> String {
114 self.url(&format!("/{}/{id}", T::KIND))
115 }
116
117 fn url(&self, path: &str) -> String {
118 format!("{}{path}", self.base_url)
119 }
120
121 fn monster_url(&self, id: Uuid) -> String {
122 self.url(&format!("/monsters/{id}"))
123 }
124}