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