api_binding/
endpoint.rs

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    /// HTTP Method to hit the endpoint with
11    fn method(&self) -> Method;
12
13    /// Path to endpoint
14    fn endpoint(&self) -> Cow<'static, str>;
15
16    /// Parameters to hit the endpoint with
17    fn parameters(&self) -> QueryParams {
18        QueryParams::default()
19    }
20
21    /// Body to hit the endpoint with
22    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}