http_api_client_endpoint/
lib.rs

1use core::time::Duration;
2
3#[cfg(feature = "dyn-clone")]
4use dyn_clone::{clone_trait_object, DynClone};
5pub use http::{self, Request, Response};
6
7pub type Body = Vec<u8>;
8pub const MIME_APPLICATION_JSON: &str = "application/json";
9
10//
11//
12//
13#[cfg(feature = "dyn-clone")]
14pub trait Endpoint: DynClone {
15    type RenderRequestError: std::error::Error + Send + Sync + 'static;
16
17    type ParseResponseOutput;
18    type ParseResponseError: std::error::Error + Send + Sync + 'static;
19
20    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError>;
21
22    fn parse_response(
23        &self,
24        response: Response<Body>,
25    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError>;
26}
27
28#[cfg(not(feature = "dyn-clone"))]
29pub trait Endpoint {
30    type RenderRequestError: std::error::Error + Send + Sync + 'static;
31
32    type ParseResponseOutput;
33    type ParseResponseError: std::error::Error + Send + Sync + 'static;
34
35    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError>;
36
37    fn parse_response(
38        &self,
39        response: Response<Body>,
40    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError>;
41}
42
43#[cfg(feature = "dyn-clone")]
44clone_trait_object!(<RenderRequestError, ParseResponseOutput, ParseResponseError> Endpoint<RenderRequestError = RenderRequestError, ParseResponseOutput = ParseResponseOutput, ParseResponseError = ParseResponseError>);
45
46impl<RenderRequestError, ParseResponseOutput, ParseResponseError> core::fmt::Debug
47    for dyn Endpoint<
48        RenderRequestError = RenderRequestError,
49        ParseResponseOutput = ParseResponseOutput,
50        ParseResponseError = ParseResponseError,
51    >
52{
53    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54        f.debug_struct("Endpoint").finish()
55    }
56}
57
58impl<RenderRequestError, ParseResponseOutput, ParseResponseError> core::fmt::Debug
59    for dyn Endpoint<
60            RenderRequestError = RenderRequestError,
61            ParseResponseOutput = ParseResponseOutput,
62            ParseResponseError = ParseResponseError,
63        > + Send
64        + Sync
65{
66    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
67        f.debug_struct("Endpoint").finish()
68    }
69}
70
71//
72//
73//
74#[cfg(feature = "dyn-clone")]
75pub trait RetryableEndpoint: DynClone {
76    type RetryReason: Send + Sync + Clone;
77
78    type RenderRequestError: std::error::Error + Send + Sync + 'static;
79
80    type ParseResponseOutput;
81    type ParseResponseError: std::error::Error + Send + Sync + 'static;
82
83    fn render_request(
84        &self,
85        retry: Option<&RetryableEndpointRetry<Self::RetryReason>>,
86    ) -> Result<Request<Body>, Self::RenderRequestError>;
87
88    fn parse_response(
89        &self,
90        response: Response<Body>,
91        retry: Option<&RetryableEndpointRetry<Self::RetryReason>>,
92    ) -> Result<Result<Self::ParseResponseOutput, Self::RetryReason>, Self::ParseResponseError>;
93
94    fn max_retry_count(&self) -> usize {
95        3
96    }
97
98    fn next_retry_in(&self, retry: &RetryableEndpointRetry<Self::RetryReason>) -> Duration {
99        match retry.count {
100            0..=2 => Duration::from_millis(500),
101            _ => Duration::from_secs(1),
102        }
103    }
104}
105
106#[cfg(not(feature = "dyn-clone"))]
107pub trait RetryableEndpoint {
108    type RetryReason: Send + Sync + Clone;
109
110    type RenderRequestError: std::error::Error + Send + Sync + 'static;
111
112    type ParseResponseOutput;
113    type ParseResponseError: std::error::Error + Send + Sync + 'static;
114
115    fn render_request(
116        &self,
117        retry: Option<&RetryableEndpointRetry<Self::RetryReason>>,
118    ) -> Result<Request<Body>, Self::RenderRequestError>;
119
120    fn parse_response(
121        &self,
122        response: Response<Body>,
123        retry: Option<&RetryableEndpointRetry<Self::RetryReason>>,
124    ) -> Result<Result<Self::ParseResponseOutput, Self::RetryReason>, Self::ParseResponseError>;
125
126    fn max_retry_count(&self) -> usize {
127        3
128    }
129
130    fn next_retry_in(&self, retry: &RetryableEndpointRetry<Self::RetryReason>) -> Duration {
131        match retry.count {
132            0 | 1 | 2 => Duration::from_millis(500),
133            _ => Duration::from_secs(1),
134        }
135    }
136}
137
138#[cfg(feature = "dyn-clone")]
139clone_trait_object!(<RetryReason, RenderRequestError, ParseResponseOutput, ParseResponseError> RetryableEndpoint<RetryReason = RetryReason, RenderRequestError = RenderRequestError, ParseResponseOutput = ParseResponseOutput, ParseResponseError = ParseResponseError>);
140
141impl<RetryReason, RenderRequestError, ParseResponseOutput, ParseResponseError> core::fmt::Debug
142    for dyn RetryableEndpoint<
143        RetryReason = RetryReason,
144        RenderRequestError = RenderRequestError,
145        ParseResponseOutput = ParseResponseOutput,
146        ParseResponseError = ParseResponseError,
147    >
148{
149    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
150        f.debug_struct("RetryableEndpoint").finish()
151    }
152}
153
154impl<RetryReason, RenderRequestError, ParseResponseOutput, ParseResponseError> core::fmt::Debug
155    for dyn RetryableEndpoint<
156            RetryReason = RetryReason,
157            RenderRequestError = RenderRequestError,
158            ParseResponseOutput = ParseResponseOutput,
159            ParseResponseError = ParseResponseError,
160        > + Send
161        + Sync
162{
163    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
164        f.debug_struct("RetryableEndpoint").finish()
165    }
166}
167
168//
169pub struct RetryableEndpointRetry<T> {
170    pub count: usize,
171    pub reason: T,
172}
173
174impl<T> core::fmt::Debug for RetryableEndpointRetry<T>
175where
176    T: core::fmt::Debug,
177{
178    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
179        f.debug_struct("RetryableEndpointRetry")
180            .field("count", &self.count)
181            .field("reason", &self.reason)
182            .finish()
183    }
184}
185
186impl<T> RetryableEndpointRetry<T> {
187    pub fn new(count: usize, reason: T) -> Self {
188        Self { count, reason }
189    }
190}