http_api_client_endpoint/
lib.rs1use 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#[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#[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
168pub 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}