1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::borrow::Cow;
use async_trait::async_trait;
use bytes::Bytes;
use http::{Request, Response};
use std::error::Error;
use thiserror::Error;
pub trait Endpoint {
type Request: serde::Serialize + Send + Sync;
type Response: serde::de::DeserializeOwned + Send + Sync;
fn endpoint(&self) -> Cow<'static, str>;
fn body(&self) -> &Self::Request;
fn method(&self) -> http::Method {
http::Method::POST
}
}
#[async_trait]
pub trait Query<C> {
type Result;
async fn execute(self, client: &C) -> Self::Result;
}
#[derive(Debug, Error)]
pub enum QueryError<E>
where
E: Error + Send + Sync + 'static,
{
#[error("client error: {}", source)]
Client {
source: E,
},
#[error("could not parse JSON response: {}", source)]
Json {
#[from]
source: serde_json::Error,
},
#[error("failed to create form data: {}", source)]
Body {
#[from]
source: http::Error,
},
}
impl<E> QueryError<E>
where
E: Error + Send + Sync + 'static,
{
pub fn client(source: E) -> Self {
QueryError::Client { source }
}
}
#[async_trait]
impl<T, C> Query<C> for T
where
T: Endpoint + Send + Sync,
C: Client + Send + Sync,
{
type Result = Result<T::Response, QueryError<C::Error>>;
async fn execute(self, client: &C) -> Self::Result {
let body = serde_json::to_vec(self.body())?;
let http_req = http::Request::builder()
.method(self.method())
.uri(String::from(self.endpoint()))
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.body(body.into())?;
let response = client.execute(http_req).await.map_err(QueryError::client)?;
Ok(serde_json::from_slice(response.body())?)
}
}
#[async_trait]
pub trait Client {
type Error: Error + Send + Sync + 'static;
async fn execute(&self, req: Request<Bytes>) -> Result<Response<Bytes>, Self::Error>;
}