opennode_client/
client.rs

1/// About Authentication:
2///
3/// The OpenNode API uses API Keys to authenticate requests.
4/// You can view and manage your API Keys in the Integrations dashboard.
5/// Development mode keys are generated on the Development environment,
6/// while Production mode keys are generated on the Production environment.
7///
8/// Authentication to the API is performed with a key.
9/// Provide your API key on on the Authorization header.
10///
11/// All API requests must be made over HTTPS.
12/// Calls made over plain HTTP will fail.
13/// API Requests without authentication will also fail.
14///
15/// | Permission                        | Invoice | Read | Withdrawals |
16/// |-----------------------------------|---------|------|-------------|
17/// | Create charge & fetch charge info |   ✅    |  ✅  |    ✅       |
18/// | Fetch charges & withdrawals info  |   ❌    |  ✅  |    ✅       |
19/// | Initiate withdrawals              |   ❌    |  ❌  |    ✅       |
20use serde::de::DeserializeOwned;
21use serde::{Deserialize, Serialize};
22use serde_json;
23
24use crate::error::Error;
25
26pub struct Client {
27    client: reqwest::Client,
28    host: String,
29    api_key: String,
30}
31
32#[derive(Debug, Deserialize)]
33pub struct Data<T> {
34    pub data: T,
35}
36
37impl Client {
38    /// Creates a new client pointed to `https://api.opennode.co`
39    pub fn new(apikey: impl Into<String>) -> Client {
40        Client::from_url("https://api.opennode.co", apikey)
41    }
42
43    /// Creates a new client posted to a custom host.
44    pub fn from_url(host: impl Into<String>, apikey: impl Into<String>) -> Client {
45        Client {
46            client: reqwest::Client::new(),
47            api_key: apikey.into(),
48            host: host.into(),
49        }
50    }
51
52    pub fn with_api_key(self, apikey: impl Into<String>) -> Client {
53        let mut clt = self;
54        clt.api_key = apikey.into();
55        clt
56    }
57
58    pub fn with_host(self, host: impl Into<String>) -> Client {
59        let mut clt = self;
60        clt.host = host.into();
61        clt
62    }
63
64    pub async fn get<S, T>(&self, path: &str, params: Option<S>) -> Result<T, Error>
65    where
66        S: Into<String>,
67        T: DeserializeOwned,
68    {
69        let p = params.map_or("".to_string(), |par| (par.into()));
70        let url = self.host.to_owned() + path + &p;
71
72        let res = self.client.get(&url)
73            .header("Authorization", self.api_key.clone())
74            .send()
75            .await
76            .map_err(|e| Error::Http(e))?;
77
78        if res.status().is_success() {
79            let d: Data<T> = res.json().await.map_err(|e| Error::Http(e))?;
80            return Ok(d.data);
81        }
82
83        let e: opennode::error::RequestError = res.json().await.map_err(|e|{Error::Http(e)})?;
84        Err(Error::Opennode(e))
85    }
86
87
88    pub async fn post<P, T>(&self, path: &str, payload: Option<P>) -> Result<T, Error>
89    where
90        P: Serialize,
91        T: DeserializeOwned,
92    {
93
94        let mut body: Vec<u8> = Vec::new();
95        let mut content_type = "".to_string();
96        if let Some(p) = payload {
97            body = serde_json::to_vec(&p).unwrap();
98            content_type = "application/json".to_string();
99        }
100        let url = self.host.to_owned() + path;
101
102        let res = self.client.post(&url)
103            .header("Content-Type", content_type)
104            .header("Authorization", self.api_key.clone())
105            .body(body)
106            .send()
107            .await
108            .map_err(|e| Error::Http(e))?;
109
110        if res.status().is_success() {
111            let d: Data<T> = res.json().await.map_err(|e| Error::Http(e))?;
112            return Ok(d.data);
113        }
114
115        let e: opennode::error::RequestError = res.json().await.map_err(|e|{Error::Http(e)})?;
116        Err(Error::Opennode(e))
117    }
118}