rustify/client.rs
1//! Contains the [Client] trait for executing
2//! [Endpoints][crate::endpoint::Endpoint].
3use crate::errors::ClientError;
4use async_trait::async_trait;
5use http::{Request, Response};
6use std::ops::RangeInclusive;
7
8/// An array of HTTP response codes which indicate a successful response
9pub const HTTP_SUCCESS_CODES: RangeInclusive<u16> = 200..=208;
10
11/// Represents an HTTP client which is capable of executing
12/// [Endpoints][crate::endpoint::Endpoint] by sending the [Request] generated
13/// by the Endpoint and returning a [Response].
14#[async_trait]
15pub trait Client: Sync + Send {
16 /// Sends the given [Request] and returns a [Response]. Implementations
17 /// should consolidate all errors into the [ClientError] type.
18 async fn send(&self, req: Request<Vec<u8>>) -> Result<Response<Vec<u8>>, ClientError>;
19
20 /// Returns the base URL the client is configured with. This is used for
21 /// creating the fully qualified URLs used when executing
22 /// [Endpoints][crate::endpoint::Endpoint].
23 fn base(&self) -> &str;
24
25 /// This method provides a common interface to
26 /// [Endpoints][crate::endpoint::Endpoint] for execution.
27 // TODO: remove the allow when the upstream clippy issue is fixed:
28 // <https://github.com/rust-lang/rust-clippy/issues/12281>
29 #[allow(clippy::blocks_in_conditions)]
30 #[instrument(skip(self, req), err)]
31 async fn execute(&self, req: Request<Vec<u8>>) -> Result<Response<Vec<u8>>, ClientError> {
32 debug!(
33 "Client sending {} request to {} with {} bytes of data",
34 req.method().to_string(),
35 req.uri(),
36 req.body().len(),
37 );
38 let response = self.send(req).await?;
39
40 debug!(
41 "Client received {} response with {} bytes of body data",
42 response.status().as_u16(),
43 response.body().len()
44 );
45
46 // Check response
47 if !HTTP_SUCCESS_CODES.contains(&response.status().as_u16()) {
48 return Err(ClientError::ServerResponseError {
49 code: response.status().as_u16(),
50 content: String::from_utf8(response.body().to_vec()).ok(),
51 });
52 }
53
54 // Parse response content
55 Ok(response)
56 }
57}