speedrun_api/api/
endpoint.rs

1use std::borrow::Cow;
2
3use async_trait::async_trait;
4use http::Method;
5use serde::de::DeserializeOwned;
6
7use super::{
8    error::BodyError,
9    query::{AsyncQuery, Query},
10    query_params::QueryParams,
11    utils::{build_request, deserialize_response},
12    ApiError, AsyncClient, Client,
13};
14
15pub trait Endpoint {
16    fn method(&self) -> Method {
17        Method::GET
18    }
19
20    fn endpoint(&self) -> Cow<'static, str>;
21
22    fn query_parameters(&self) -> Result<QueryParams<'_>, BodyError> {
23        Ok(QueryParams::default())
24    }
25
26    fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
27        Ok(None)
28    }
29
30    //NOTE: Move this into a type/trait?
31    /// If this endpoint requires a valid API key
32    fn requires_authentication(&self) -> bool {
33        false
34    }
35}
36
37impl<E, T, C> Query<T, C> for E
38where
39    E: Endpoint,
40    T: DeserializeOwned,
41    C: Client,
42{
43    fn query(&self, client: &C) -> Result<T, super::ApiError<C::Error>> {
44        let (req, data) = build_request(self, client)?;
45
46        let url = req.uri_ref().cloned().unwrap_or_default();
47
48        let rsp = client.rest(req, data)?;
49
50        deserialize_response::<_>(rsp)
51            .map(|value| value.data)
52            .map_err(|err| ApiError::from_http_response(err, url))
53    }
54}
55
56#[async_trait]
57impl<E, T, C> AsyncQuery<T, C> for E
58where
59    E: Endpoint + Sync,
60    T: DeserializeOwned + 'static,
61    C: AsyncClient + Sync,
62{
63    async fn query_async(&self, client: &C) -> Result<T, ApiError<C::Error>> {
64        let (req, data) = build_request(self, client)?;
65        let url = req.uri_ref().cloned().unwrap_or_default();
66
67        let rsp = client.rest_async(req, data).await?;
68
69        deserialize_response::<_>(rsp)
70            .map(|value| value.data)
71            .map_err(|err| ApiError::from_http_response(err, url))
72    }
73}