zenlayercloud_sdk/
client.rs

1use log::debug;
2use serde::{de::DeserializeOwned, Deserialize, Serialize};
3
4use crate::{
5    credentials::AccessKeyCredential,
6    signer::{Signer, Zc2HS256Signer},
7    Error, API_DOMAIN, SDK_VERSION,
8};
9
10#[derive(Debug)]
11pub struct Request {
12    rb: reqwest::RequestBuilder,
13}
14
15impl Request {
16    pub fn build(self) -> reqwest::Result<reqwest::Request> {
17        self.rb.build()
18    }
19}
20
21/// [Responses](https://docs.console.zenlayer.com/api-reference/api-introduction/instruction/response)
22#[derive(Debug, Deserialize)]
23pub struct Response<T> {
24    #[serde(rename = "requestId")]
25    pub request_id: String,
26    /// Success response. Content are API specific.
27    pub response: Option<T>,
28    /// Failure response.
29    pub code: Option<String>,
30    pub message: Option<String>,
31}
32
33pub struct Client {
34    hc: reqwest::Client,
35    signer: Zc2HS256Signer,
36}
37
38impl Client {
39    pub fn new(credential: AccessKeyCredential) -> Self {
40        let hc = reqwest::Client::new();
41        let signer = Zc2HS256Signer::new(credential);
42        Client { hc, signer }
43    }
44
45    pub fn create_request<T>(
46        &self,
47        service: &str,
48        api_version: &str,
49        action: &str,
50        payload: &T,
51    ) -> Request
52    where
53        T: Serialize + ?Sized,
54    {
55        let host = API_DOMAIN;
56        let url = format!("https://{}/api/v2/{}", host, service);
57
58        let timestamp = format!("{}", chrono::Local::now().timestamp());
59        let rb = self
60            .hc
61            .post(&url)
62            .header("Host", host)
63            .header("x-zc-version", api_version)
64            .header("x-zc-action", action)
65            .header("x-zc-timestamp", timestamp)
66            .header("x-zc-sdk-version", SDK_VERSION)
67            .header("x-zc-sdk-lang", "rust")
68            .json(payload); // set Content-Type: application/json
69        Request { rb }
70    }
71
72    pub async fn call_api<R>(&self, req: Request) -> Result<Response<R>, Error>
73    where
74        R: DeserializeOwned,
75    {
76        let mut http_req = req.build()?;
77        self.signer.sign_request(&mut http_req)?;
78        debug!("http_req={:?}", http_req);
79        let http_res = self.hc.execute(http_req).await?;
80        debug!("http_res={:?}", http_res);
81        let status = http_res.status();
82        let res: Response<R> = http_res.json().await?;
83        if status.is_success() {
84            Ok(res)
85        } else {
86            Err(Error::APIError {
87                request_id: res.request_id,
88                http_status: status.as_u16(),
89                code: res.code.unwrap_or_default(),
90                message: res.message.unwrap_or_default(),
91            })
92        }
93    }
94}