cellstate/entity/
client.rs1use anyhow::Result;
7use reqwest::Client;
8use serde::{de::DeserializeOwned, Serialize};
9use std::time::Duration;
10
11pub struct ApiClient {
13 client: Client,
14 base_url: String,
15 api_key: Option<String>,
16 tenant_id: Option<String>,
17}
18
19impl ApiClient {
20 pub fn new(base_url: String, api_key: Option<String>, tenant_id: Option<String>) -> Self {
25 let client = Client::builder()
26 .timeout(Duration::from_secs(30))
27 .build()
28 .expect("failed to build HTTP client");
29 Self {
30 client,
31 base_url,
32 api_key,
33 tenant_id,
34 }
35 }
36
37 fn request(&self, method: reqwest::Method, path: &str) -> reqwest::RequestBuilder {
39 let url = format!("{}{}", self.base_url, path);
40 let mut req = self.client.request(method, &url);
41 if let Some(key) = &self.api_key {
42 req = req.header("x-api-key", key);
43 }
44 if let Some(tid) = &self.tenant_id {
45 req = req.header("x-tenant-id", tid);
46 }
47 req
48 }
49
50 pub async fn get<T: DeserializeOwned>(&self, path: &str) -> Result<T> {
52 let resp = self.request(reqwest::Method::GET, path).send().await?;
53 let status = resp.status();
54 if !status.is_success() {
55 let body = resp.text().await.unwrap_or_default();
56 anyhow::bail!("API error {status}: {body}");
57 }
58 Ok(resp.json().await?)
59 }
60
61 pub async fn get_raw(&self, path: &str) -> Result<serde_json::Value> {
63 self.get(path).await
64 }
65
66 pub async fn post<T: DeserializeOwned, B: Serialize>(&self, path: &str, body: &B) -> Result<T> {
68 let resp = self
69 .request(reqwest::Method::POST, path)
70 .json(body)
71 .send()
72 .await?;
73 let status = resp.status();
74 if !status.is_success() {
75 let body = resp.text().await.unwrap_or_default();
76 anyhow::bail!("API error {status}: {body}");
77 }
78 Ok(resp.json().await?)
79 }
80
81 pub async fn post_raw<B: Serialize>(&self, path: &str, body: &B) -> Result<serde_json::Value> {
83 self.post(path, body).await
84 }
85
86 pub async fn post_no_body<T: DeserializeOwned>(&self, path: &str) -> Result<T> {
88 let resp = self.request(reqwest::Method::POST, path).send().await?;
89 let status = resp.status();
90 if !status.is_success() {
91 let body = resp.text().await.unwrap_or_default();
92 anyhow::bail!("API error {status}: {body}");
93 }
94 Ok(resp.json().await?)
95 }
96
97 pub async fn post_no_body_raw(&self, path: &str) -> Result<serde_json::Value> {
99 self.post_no_body(path).await
100 }
101
102 pub async fn patch<T: DeserializeOwned, B: Serialize>(
104 &self,
105 path: &str,
106 body: &B,
107 ) -> Result<T> {
108 let resp = self
109 .request(reqwest::Method::PATCH, path)
110 .json(body)
111 .send()
112 .await?;
113 let status = resp.status();
114 if !status.is_success() {
115 let body = resp.text().await.unwrap_or_default();
116 anyhow::bail!("API error {status}: {body}");
117 }
118 Ok(resp.json().await?)
119 }
120
121 pub async fn delete(&self, path: &str) -> Result<()> {
123 let resp = self.request(reqwest::Method::DELETE, path).send().await?;
124 let status = resp.status();
125 if !status.is_success() {
126 let body = resp.text().await.unwrap_or_default();
127 anyhow::bail!("API error {status}: {body}");
128 }
129 Ok(())
130 }
131}