1use reqwest::{
2 Body, Client, Response,
3 header::{CONTENT_TYPE, HeaderValue},
4};
5use serde::{Serialize, de::DeserializeOwned};
6use serde_json::to_value;
7
8use crate::utils::Error;
9
10#[derive(Debug, Clone)]
11pub struct Session {
12 pub reqwest_client: Client,
13 pub base_url: String,
14}
15
16pub trait ResponseData<T: Sized> {
17 fn from_response(response: Response) -> impl Future<Output = Result<T, Error>>;
18}
19impl<Data: DeserializeOwned> ResponseData<Data> for Data {
20 async fn from_response(response: Response) -> Result<Self, Error> {
21 serde_json::from_slice(&response.bytes().await.map_err(Error::ReqwestError)?)
22 .map_err(Error::SerdeJsonError)
23 }
24}
25
26pub trait QueryData {
27 fn create_query(&self) -> Result<Vec<(String, String)>, Error>;
28}
29impl<Data: Serialize> QueryData for Data {
30 fn create_query(&self) -> Result<Vec<(String, String)>, Error> {
31 Ok(to_value(self)
32 .map_err(Error::SerdeJsonError)?
33 .as_object()
34 .map(|x| {
35 x.into_iter()
36 .filter_map(|(key, value)| match value {
37 serde_json::Value::String(s) => Some((key.clone(), s.clone())),
38 serde_json::Value::Number(n) => Some((key.clone(), n.to_string())),
39 _ => None,
40 })
41 .collect()
42 })
43 .unwrap_or(vec![]))
44 }
45}
46
47pub trait BodyData {
48 fn create_body(&self) -> Result<Body, Error>;
49}
50impl<Data: Serialize> BodyData for Data {
51 fn create_body(&self) -> Result<Body, Error> {
52 Ok(serde_json::to_vec(&self)
53 .map_err(Error::SerdeJsonError)?
54 .into())
55 }
56}
57
58#[derive(Default)]
59pub struct Empty {}
60impl ResponseData<Empty> for Empty {
61 async fn from_response(_response: Response) -> Result<Self, Error> {
62 Ok(Self {})
63 }
64}
65impl QueryData for Empty {
66 fn create_query(&self) -> Result<Vec<(String, String)>, Error> {
67 Ok(vec![])
68 }
69}
70impl BodyData for Empty {
71 fn create_body(&self) -> Result<Body, Error> {
72 Ok(Body::default())
73 }
74}
75
76#[derive(Debug, Clone)]
77pub struct SessionGetInput<'a, Path, Query: QueryData> {
78 pub session: &'a Session,
79 pub path: Path,
80 pub query: Query,
81}
82pub type SessionGetOutput<Output> = Result<Output, Error>;
83#[derive(Debug, Clone)]
84pub struct SessionPostInput<'a, Path, Data: BodyData> {
85 pub session: &'a Session,
86 pub path: Path,
87 pub data: Data,
88}
89pub type SessionPostOutput<Output> = Result<Output, Error>;
90
91impl<'a> SessionGetInput<'a, Empty, Empty> {
92 pub fn new(session: &'a Session) -> Self {
93 Self {
94 session,
95 path: Empty::default(),
96 query: Empty::default(),
97 }
98 }
99}
100impl<'a, Path> SessionGetInput<'a, Path, Empty> {
101 pub fn new_with_path(session: &'a Session, path: Path) -> Self {
102 Self {
103 session,
104 path,
105 query: Empty::default(),
106 }
107 }
108}
109impl<'a, Query: Serialize> SessionGetInput<'a, Empty, Query> {
110 pub fn new_with_query(session: &'a Session, query: Query) -> Self {
111 Self {
112 session,
113 path: Empty::default(),
114 query,
115 }
116 }
117}
118
119impl<'a> SessionPostInput<'a, Empty, Empty> {
120 pub fn new(session: &'a Session) -> Self {
121 Self {
122 session,
123 path: Empty::default(),
124 data: Empty::default(),
125 }
126 }
127}
128impl<'a, Path> SessionPostInput<'a, Path, Empty> {
129 pub fn new_with_path(session: &'a Session, path: Path) -> Self {
130 Self {
131 session,
132 path,
133 data: Empty::default(),
134 }
135 }
136}
137impl<'a, Data: Serialize> SessionPostInput<'a, Empty, Data> {
138 pub fn new_with_data(session: &'a Session, data: Data) -> Self {
139 Self {
140 session,
141 path: Empty::default(),
142 data,
143 }
144 }
145}
146
147pub async fn session_get<
148 Output: ResponseData<Output>,
149 Path,
150 Query: QueryData,
151 PathOutput: Into<String>,
152>(
153 input: SessionGetInput<'_, Path, Query>,
154 scope: String,
155 path: fn(Path) -> PathOutput,
156) -> SessionGetOutput<Output> {
157 let session = input.session;
158 Output::from_response(
159 session
160 .reqwest_client
161 .get(format!(
162 "{}{}{}",
163 session.base_url,
164 scope,
165 path(input.path).into()
166 ))
167 .query(&input.query.create_query()?)
168 .send()
169 .await
170 .map_err(Error::ReqwestError)?,
171 )
172 .await
173}
174
175pub async fn session_post<
176 Output: ResponseData<Output>,
177 Path,
178 Data: BodyData,
179 PathOutput: Into<String>,
180>(
181 input: SessionPostInput<'_, Path, Data>,
182 scope: String,
183 path: fn(Path) -> PathOutput,
184) -> SessionPostOutput<Output> {
185 let session = input.session;
186 Output::from_response(
187 session
188 .reqwest_client
189 .post(format!(
190 "{}{}{}",
191 session.base_url,
192 scope,
193 path(input.path).into()
194 ))
195 .header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
196 .body(input.data.create_body()?)
197 .send()
198 .await
199 .map_err(Error::ReqwestError)?,
200 )
201 .await
202}