rs_firebase_admin_sdk/client/
mod.rs1pub mod error;
4pub mod url_params;
5
6use crate::credentials::get_headers;
7use bytes::Bytes;
8use error::{ApiClientError, FireBaseAPIErrorResponse};
9use error_stack::{Report, ResultExt};
10use google_cloud_auth::credentials::Credentials;
11use http::Method;
12use serde::{Serialize, de::DeserializeOwned};
13use std::future::Future;
14use std::iter::Iterator;
15use url_params::UrlParams;
16
17pub trait ApiHttpClient: Send + Sync + 'static {
18 fn send_request<ResponseT: Send + DeserializeOwned>(
19 &self,
20 uri: String,
21 method: Method,
22 ) -> impl Future<Output = Result<ResponseT, Report<ApiClientError>>> + Send;
23
24 fn send_request_with_params<
25 ResponseT: DeserializeOwned + Send,
26 ParamsT: Iterator<Item = (String, String)> + Send,
27 >(
28 &self,
29 uri: String,
30 params: ParamsT,
31 method: Method,
32 ) -> impl Future<Output = Result<ResponseT, Report<ApiClientError>>> + Send;
33
34 fn send_request_body<RequestT: Serialize + Send, ResponseT: DeserializeOwned + Send>(
35 &self,
36 uri: String,
37 method: Method,
38 request_body: RequestT,
39 ) -> impl Future<Output = Result<ResponseT, Report<ApiClientError>>> + Send;
40
41 fn send_request_body_get_bytes<RequestT: Serialize + Send>(
42 &self,
43 uri: String,
44 method: Method,
45 request_body: RequestT,
46 ) -> impl Future<Output = Result<Bytes, Report<ApiClientError>>> + Send;
47
48 fn send_request_body_empty_response<RequestT: Serialize + Send>(
49 &self,
50 uri: String,
51 method: Method,
52 request_body: RequestT,
53 ) -> impl Future<Output = Result<(), Report<ApiClientError>>> + Send;
54}
55
56trait SetReqBody<T: Serialize> {
57 fn set_request_body(self, body: Option<T>) -> Self;
58}
59
60impl<T: Serialize> SetReqBody<T> for reqwest::RequestBuilder {
61 fn set_request_body(self, body: Option<T>) -> Self {
62 if let Some(body) = body {
63 return self.json(&body);
64 }
65
66 self
67 }
68}
69
70pub struct ReqwestApiClient {
71 client: reqwest::Client,
72 credentials: Credentials,
73}
74
75impl ReqwestApiClient {
76 pub fn new(client: reqwest::Client, credentials: Credentials) -> Self {
77 Self {
78 client,
79 credentials,
80 }
81 }
82
83 async fn handle_response(
84 resp: reqwest::Response,
85 ) -> Result<reqwest::Response, Report<ApiClientError>> {
86 if resp.status() != reqwest::StatusCode::OK {
87 let error_response: FireBaseAPIErrorResponse = resp
88 .json()
89 .await
90 .change_context(ApiClientError::FailedToReceiveResponse)?;
91
92 return Err(Report::new(ApiClientError::ServerError(
93 error_response.error,
94 )));
95 }
96
97 Ok(resp)
98 }
99
100 async fn handle_request<B: Serialize + Send>(
101 &self,
102 url: &str,
103 method: Method,
104 body: Option<B>,
105 ) -> Result<reqwest::Response, Report<ApiClientError>> {
106 self.client
107 .request(method, url)
108 .headers(
109 get_headers(&self.credentials)
110 .await
111 .change_context(ApiClientError::FailedToSendRequest)?,
112 )
113 .set_request_body(body)
114 .send()
115 .await
116 .change_context(ApiClientError::FailedToSendRequest)
117 }
118}
119
120impl ApiHttpClient for ReqwestApiClient {
121 async fn send_request<ResponseT: Send + DeserializeOwned>(
122 &self,
123 url: String,
124 method: Method,
125 ) -> Result<ResponseT, Report<ApiClientError>> {
126 Self::handle_response(self.handle_request::<()>(&url, method, None).await?)
127 .await?
128 .json()
129 .await
130 .change_context(ApiClientError::FailedToReceiveResponse)
131 }
132
133 async fn send_request_with_params<
134 ResponseT: DeserializeOwned + Send,
135 ParamsT: Iterator<Item = (String, String)> + Send,
136 >(
137 &self,
138 url: String,
139 params: ParamsT,
140 method: Method,
141 ) -> Result<ResponseT, Report<ApiClientError>> {
142 let url: String = url + ¶ms.into_url_params();
143 Self::handle_response(self.handle_request::<()>(&url, method, None).await?)
144 .await?
145 .json()
146 .await
147 .change_context(ApiClientError::FailedToReceiveResponse)
148 }
149
150 async fn send_request_body<RequestT: Serialize + Send, ResponseT: DeserializeOwned + Send>(
151 &self,
152 url: String,
153 method: Method,
154 request_body: RequestT,
155 ) -> Result<ResponseT, Report<ApiClientError>> {
156 Self::handle_response(
157 self.handle_request(&url, method, Some(request_body))
158 .await?,
159 )
160 .await?
161 .json()
162 .await
163 .change_context(ApiClientError::FailedToReceiveResponse)
164 }
165
166 async fn send_request_body_get_bytes<RequestT: Serialize + Send>(
167 &self,
168 url: String,
169 method: Method,
170 request_body: RequestT,
171 ) -> Result<Bytes, Report<ApiClientError>> {
172 Self::handle_response(
173 self.handle_request(&url, method, Some(request_body))
174 .await?,
175 )
176 .await?
177 .bytes()
178 .await
179 .change_context(ApiClientError::FailedToReceiveResponse)
180 }
181
182 async fn send_request_body_empty_response<RequestT: Serialize + Send>(
183 &self,
184 url: String,
185 method: Method,
186 request_body: RequestT,
187 ) -> Result<(), Report<ApiClientError>> {
188 Self::handle_response(
189 self.handle_request(&url, method, Some(request_body))
190 .await?,
191 )
192 .await?;
193
194 Ok(())
195 }
196}