1use af_core::prelude::*;
10
11const URL: &str = "https://slack.com/api/";
13
14pub struct Client {
16 authorization: String,
17 http: reqwest::Client,
18}
19
20impl Client {
21 pub fn new(token: impl AsRef<str>) -> Self {
23 Self { authorization: format!("Bearer {}", token.as_ref()), http: default() }
24 }
25
26 pub async fn get<Q, O>(&self, method: &str, query: &Q) -> Result<Result<O, ErrorResponse>>
28 where
29 Q: Serialize,
30 O: for<'a> Deserialize<'a>,
31 {
32 let req = self
33 .http
34 .get(&format!("{}{}?{}", URL, method, serde_qs::to_string(query).unwrap()))
35 .header("Authorization", &self.authorization);
36
37 let mut res: ResponseProps = req.send().await?.json().await?;
38 let ok = res.remove("ok").and_then(|v| v.as_bool()).unwrap_or_default();
39
40 Ok(match ok {
41 true => Ok(json::from_value(json::Value::Object(res))?),
42 false => Err(json::from_value(json::Value::Object(res))?),
43 })
44 }
45
46 pub async fn post<I, O>(&self, method: &str, body: &I) -> Result<Result<O, ErrorResponse>>
48 where
49 I: Serialize,
50 O: for<'a> Deserialize<'a>,
51 {
52 let req = self
53 .http
54 .post(&format!("{}{}", URL, method))
55 .header("Authorization", &self.authorization)
56 .json(body);
57
58 let mut res: ResponseProps = req.send().await?.json().await?;
59 let ok = res.remove("ok").and_then(|v| v.as_bool()).unwrap_or_default();
60
61 Ok(match ok {
62 true => Ok(json::from_value(json::Value::Object(res))?),
63 false => Err(json::from_value(json::Value::Object(res))?),
64 })
65 }
66}
67
68#[derive(Debug, Error)]
70pub enum Error {
71 #[error("invalid response body: {0}")]
73 InvalidResponse(#[from] json::Error),
74 #[error(transparent)]
76 RequestFailed(#[from] reqwest::Error),
77}
78
79pub type Result<T = (), E = Error> = std::result::Result<T, E>;
81
82pub type ResponseProps = json::Map<String, json::Value>;
84
85#[derive(Debug, Deserialize, Serialize)]
87pub struct ErrorResponse {
88 pub error: String,
90 #[serde(flatten)]
92 pub props: ResponseProps,
93}
94
95impl Display for ErrorResponse {
96 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97 let json = match f.alternate() {
98 true => json::to_string_pretty(self).unwrap(),
99 false => json::to_string(self).unwrap(),
100 };
101
102 Display::fmt(&json, f)
103 }
104}