circle_compliance/
client.rs1use crate::{
4 error::Error,
5 models::{
6 common::ApiErrorBody,
7 screening::{
8 BlockchainAddressScreeningResponse, ScreenAddressEnvelope, ScreenAddressRequest,
9 },
10 },
11};
12
13pub struct ComplianceClient {
15 base_url: String,
16 api_key: String,
17 http: hpx::Client,
18}
19
20impl std::fmt::Debug for ComplianceClient {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.debug_struct("ComplianceClient")
23 .field("base_url", &self.base_url)
24 .field("api_key", &"<redacted>")
25 .finish_non_exhaustive()
26 }
27}
28
29impl ComplianceClient {
30 pub fn new(api_key: impl Into<String>) -> Self {
32 Self::with_base_url(api_key, "https://api.circle.com")
33 }
34
35 pub fn with_base_url(api_key: impl Into<String>, base_url: impl Into<String>) -> Self {
37 Self { base_url: base_url.into(), api_key: api_key.into(), http: hpx::Client::new() }
38 }
39
40 async fn post<T, B>(&self, path: &str, body: &B) -> Result<T, Error>
42 where
43 T: serde::de::DeserializeOwned,
44 B: serde::Serialize + ?Sized,
45 {
46 let url = format!("{}{}", self.base_url, path);
47 let resp = self
48 .http
49 .post(&url)
50 .header("Authorization", format!("Bearer {}", self.api_key))
51 .header("X-Request-Id", uuid::Uuid::new_v4().to_string())
52 .json(body)
53 .send()
54 .await
55 .map_err(|e| Error::Http(e.to_string()))?;
56
57 if resp.status().is_success() {
58 resp.json::<T>().await.map_err(|e| Error::Http(e.to_string()))
59 } else {
60 let err: ApiErrorBody = resp.json().await.map_err(|e| Error::Http(e.to_string()))?;
61 Err(Error::Api { code: err.code, message: err.message })
62 }
63 }
64
65 pub async fn screen_address(
72 &self,
73 req: &ScreenAddressRequest,
74 ) -> Result<BlockchainAddressScreeningResponse, Error> {
75 let envelope: ScreenAddressEnvelope =
76 self.post("/v1/w3s/compliance/screening/addresses", req).await?;
77 Ok(envelope.data)
78 }
79}