arkecosystem_client/http/
client.rs

1use api::models::{RequestError, Response};
2use api::Result;
3use reqwest::header::{HeaderMap, HeaderValue};
4use reqwest::{RequestBuilder, Url};
5use serde::de::DeserializeOwned;
6use serde::ser::Serialize;
7use serde_json::{from_str, from_value, to_string};
8use std::borrow::Borrow;
9use std::collections::HashMap;
10
11#[derive(Clone, Debug)]
12pub struct Client {
13    pub host: String,
14    client: ::reqwest::Client,
15    headers: HeaderMap,
16}
17
18impl Client {
19    pub fn new(host: &str) -> Client {
20        let mut headers = HeaderMap::new();
21        headers.insert("content-type", HeaderValue::from_static("application/json"));
22
23        Client {
24            host: host.to_owned(),
25            client: ::reqwest::Client::new(),
26            headers,
27        }
28    }
29
30    pub fn set_version(&mut self, version: &'static str) {
31        self.headers
32            .insert("API-Version", HeaderValue::from_static(version));
33    }
34
35    pub fn get<T: DeserializeOwned>(&self, endpoint: &str) -> Result<T> {
36        let url = Url::parse(&format!("{}{}", self.host, endpoint))?;
37        self.internal_get(&url)
38    }
39
40    pub fn get_with_params<T, I, K, V>(&self, endpoint: &str, parameters: I) -> Result<T>
41    where
42        T: DeserializeOwned,
43        I: IntoIterator,
44        I::Item: Borrow<(K, V)>,
45        K: AsRef<str>,
46        V: AsRef<str>,
47    {
48        let url = Url::parse_with_params(&format!("{}{}", self.host, endpoint), parameters)?;
49        self.internal_get(&url)
50    }
51
52    pub fn post<T, V>(&self, endpoint: &str, payload: Option<HashMap<&str, V>>) -> Result<T>
53    where
54        T: DeserializeOwned,
55        V: Serialize,
56    {
57        let url = Url::parse(&format!("{}{}", self.host, endpoint))?;
58        self.internal_post(&url, payload)
59    }
60
61    pub fn post_with_params<T, H, I, K, V>(
62        &self,
63        endpoint: &str,
64        payload: Option<HashMap<&str, H>>,
65        parameters: I,
66    ) -> Result<T>
67    where
68        T: DeserializeOwned,
69        H: Serialize,
70        I: IntoIterator,
71        I::Item: Borrow<(K, V)>,
72        K: AsRef<str>,
73        V: AsRef<str>,
74    {
75        let url = Url::parse_with_params(&format!("{}{}", self.host, endpoint), parameters)?;
76        self.internal_post(&url, payload)
77    }
78
79    fn internal_get<T: DeserializeOwned>(&self, url: &Url) -> Result<T> {
80        let builder = self.client.get(url.as_str());
81        self.send(builder)
82    }
83
84    fn internal_post<T, V>(&self, url: &Url, payload: Option<HashMap<&str, V>>) -> Result<T>
85    where
86        T: DeserializeOwned,
87        V: Serialize,
88    {
89        let builder = self.client.post(url.as_str());
90
91        let body = payload.map_or_else(|| Ok(String::default()), |v| to_string(&v));
92
93        self.send(builder.body(body?))
94    }
95
96    fn send<T: DeserializeOwned>(&self, builder: RequestBuilder) -> Result<T> {
97        let response = builder.headers(self.headers.clone()).send()?.text()?;
98        let value: serde_json::Value = from_str(&response)?;
99
100        // Try to deserialize into T. If it fails, assume the API returned
101        // an error.
102        let parsed = from_value::<Response<T>>(value.clone());
103        match parsed {
104            Ok(item) => Ok(item),
105            Err(_) => {
106                // Assume the API returned a RequestError.
107                let request_error = from_value::<RequestError>(value)?;
108                Err(request_error.into())
109            }
110        }
111    }
112}