netsuite/
requester.rs

1use std::collections::HashMap;
2
3use crate::config::Config;
4use crate::oauth1;
5use crate::params::Params;
6use crate::response::Response;
7use crate::Error;
8use http::Method;
9use log::debug;
10
11#[derive(Debug, Clone)]
12pub struct Requester {
13    config: Config,
14    base_url: String,
15    algorithm: oauth1::Algorithm,
16}
17
18impl Requester {
19    pub fn new(config: Config, base_url: String) -> Self {
20        Self {
21            config,
22            base_url,
23            algorithm: oauth1::Algorithm::Sha256,
24        }
25    }
26
27    pub fn with_base_url(self, base_url: String) -> Self {
28        Self { base_url, ..self }
29    }
30
31    pub fn with_algorithm(self, algorithm: oauth1::Algorithm) -> Self {
32        Self { algorithm, ..self }
33    }
34
35    fn make_url(&self, endpoint: &str) -> String {
36        format!("{}/{}", self.base_url, endpoint.trim_start_matches('/'))
37    }
38
39    fn auth_header(&self, method: &Method, url: &str, params: &Option<Params>) -> String {
40        oauth1::authorize(
41            method.as_str(),
42            url,
43            &self.config.consumer,
44            Some(&self.config.token),
45            params.clone().map(|p| p.into()),
46            Some(&self.config.account),
47            self.algorithm,
48        )
49    }
50
51    pub fn request(
52        &self,
53        method: Method,
54        endpoint: &str,
55        params: Option<Params>,
56        headers: Option<Params>,
57        payload: Option<&str>,
58    ) -> Result<Response, Error> {
59        let url = self.make_url(endpoint);
60        let auth = self.auth_header(&method, &url, &params);
61
62        let mut req = ureq::request(method.as_str(), &url)
63            .set("Authorization", &auth)
64            .set("Content-Type", "application/json");
65
66        if let Some(params) = params {
67            for (k, v) in params.get() {
68                req = req.query(k, v);
69            }
70        }
71
72        if let Some(headers) = headers {
73            for (k, v) in headers.get() {
74                req = req.set(k, v);
75            }
76        }
77
78        let resp = if let Some(payload) = payload {
79            debug!("Payload: {}", payload);
80            req.send_string(payload)
81        } else {
82            req.send_string("")
83        };
84
85        let resp = match resp {
86            Ok(resp) => resp,
87            Err(ureq::Error::Status(code, resp)) => {
88                return Err(Error::HttpRequestError(
89                    code,
90                    resp.into_string().unwrap_or_default(),
91                ));
92            }
93            Err(ureq::Error::Transport(transport)) => {
94                return Err(Error::HttpTransportError(transport.to_string()));
95            }
96        };
97        let status = http::StatusCode::from_u16(resp.status()).unwrap();
98        let headers: HashMap<String, String> = resp
99            .headers_names()
100            .into_iter()
101            .filter_map(|name| resp.header(&name).map(|value| (name, value.to_owned())))
102            .collect();
103
104        let parsed = Response::new(status, headers, resp.into_string()?);
105        debug!("Response: {}", &parsed);
106        Ok(parsed)
107    }
108}