1use std::borrow::Cow;
2
3use async_trait::async_trait;
4use http::{header, Method, Request};
5use serde::de::DeserializeOwned;
6
7use crate::{query, ApiError, AsyncClient, AsyncQuery, BodyError, Client, Query, QueryParams};
8
9pub trait Endpoint {
10 fn method(&self) -> Method;
12
13 fn endpoint(&self) -> Cow<'static, str>;
15
16 fn parameters(&self) -> QueryParams {
18 QueryParams::default()
19 }
20
21 fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
23 Ok(None)
24 }
25}
26
27impl<E, T, C> Query<T, C> for E
28where
29 E: Endpoint,
30 T: DeserializeOwned,
31 C: Client,
32{
33 fn query(&self, client: &C) -> Result<T, crate::ApiError<<C>::Error>> {
34 let mut url = client.rest_endpoint(&self.endpoint())?;
35 self.parameters().add_to_url(&mut url);
36
37 let req = Request::builder()
38 .method(self.method())
39 .uri(query::url_to_http_uri(url));
40 let (req, data) = if let Some((mime, data)) = self.body()? {
41 let req = req.header(header::CONTENT_TYPE, mime);
42 (req, data)
43 } else {
44 (req, Vec::new())
45 };
46 let rsp = client.rest(req, data)?;
47 let status = rsp.status();
48 let v = if let Ok(v) = serde_json::from_slice(rsp.body()) {
49 v
50 } else {
51 return Err(ApiError::internal_error(status, rsp.body()));
52 };
53 if !status.is_success() {
54 return Err(ApiError::server_error(v));
55 }
56
57 serde_json::from_value::<T>(v).map_err(ApiError::data_type::<T>)
58 }
59}
60
61#[async_trait]
62impl<E, T, C> AsyncQuery<T, C> for E
63where
64 E: Endpoint + Sync,
65 T: DeserializeOwned + 'static,
66 C: AsyncClient + Sync,
67{
68 async fn query_async(&self, client: &C) -> Result<T, ApiError<C::Error>> {
69 let mut url = client.rest_endpoint(&self.endpoint())?;
70 self.parameters().add_to_url(&mut url);
71
72 let req = Request::builder()
73 .method(self.method())
74 .uri(query::url_to_http_uri(url));
75 let (req, data) = if let Some((mime, data)) = self.body()? {
76 let req = req.header(header::CONTENT_TYPE, mime);
77 (req, data)
78 } else {
79 (req, Vec::new())
80 };
81 let rsp = client.rest_async(req, data).await?;
82 let status = rsp.status();
83 let v = if let Ok(v) = serde_json::from_slice(rsp.body()) {
84 v
85 } else {
86 return Err(ApiError::internal_error(status, rsp.body()));
87 };
88 if !status.is_success() {
89 return Err(ApiError::server_error(v));
90 }
91
92 serde_json::from_value::<T>(v).map_err(ApiError::data_type::<T>)
93 }
94}