dimo_rust_sdk/utils/
request.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::utils::get_credentials;
use reqwest::{Client, Method};
use serde_json::Value;
use std::collections::HashMap;
use std::error::Error;

#[derive(serde::Serialize)]
pub enum QueryValue {
    Str(String),
    Bool(bool),
}

#[derive(Debug, serde::Serialize)]
pub enum BodyValue {
    String(String),
    Array(Vec<String>),
}

#[derive(Debug)]
pub struct RequestParams {
    pub method: Method,
    pub base_url: String,
    pub path: String,
    pub query_params: Option<HashMap<String, String>>,
    pub body: Option<HashMap<String, Value>>,
    pub headers: Option<HashMap<String, String>>,
}

pub struct AuthRequestParams {
    pub method: Method,
    pub base_url: String,
    pub path: String,
    pub query_params: Option<HashMap<String, String>>,
    pub body: Option<HashMap<String, Value>>,
    pub headers: Option<HashMap<String, String>>,
    pub token_type: String,
}

/// Builds the authorization header using the appropriate token from `get_credentials`.
/// `token_type` should be either "access" (for access token) or "privilege" (for privilege token).
fn build_auth_header(token_type: &str) -> Result<HashMap<String, String>, Box<dyn Error>> {
    let credentials = get_credentials()?;

    let token = match token_type {
        "access" => &credentials.access_token,
        "privilege" => &credentials.privilege_token,
        _ => return Err("Invalid token type specified. Use 'access' or 'privilege'.".into()),
    };

    let mut headers = HashMap::new();
    headers.insert("Authorization".to_string(), format!("Bearer {}", token));
    Ok(headers)
}

pub async fn make_auth_request(params: AuthRequestParams) -> Result<Value, Box<dyn Error>> {
    let auth_header = build_auth_header(&params.token_type)?;
    let mut headers = params.headers.unwrap_or_default();
    headers.extend(auth_header);

    let request_params = RequestParams {
        method: params.method,
        base_url: params.base_url,
        path: params.path,
        query_params: params.query_params,
        body: params.body,
        headers: Some(headers),
    };

    make_request(request_params).await
}

pub async fn make_request(params: RequestParams) -> Result<Value, Box<dyn Error>> {
    let client = Client::new();
    let url = format!("{}{}", params.base_url, params.path);

    let mut request_builder = match params.method {
        Method::GET => client.get(&url),
        Method::POST => client.post(&url),
        Method::PATCH => client.patch(&url),
        _ => return Err("Unsupported method".into()),
    };

    if let Some(ref query_params) = params.query_params {
        request_builder = request_builder.query(&query_params);
    };

    let use_form_body = params
        .headers
        .as_ref()
        .and_then(|headers| headers.get("Content-Type"))
        .map(|value| value.eq_ignore_ascii_case("x-www-form-urlencoded"))
        .unwrap_or(false);

    if let Some(body) = params.body {
        request_builder = if use_form_body {
            request_builder.form(&body)
        } else {
            request_builder.json(&body)
        };
    }

    if let Some(headers) = params.headers {
        for (key, value) in headers {
            request_builder = request_builder.header(&key, &value);
        }
    }

    let response_result = request_builder.send().await;

    match response_result {
        Ok(resp) => {
            if resp.status().is_success() {
                let json_response = resp.json::<Value>().await?;
                Ok(json_response)
            } else {
                let status = resp.status();
                let error_text = resp
                    .text()
                    .await
                    .unwrap_or_else(|_| "Unknown error".to_string());
                Err(format!("Error {}: {}", status, error_text).into())
            }
        }
        Err(err) => Err(format!("Request error: {}", err).into()),
    }
}