ccxt_core/base_exchange/
requests.rs1use crate::error::Error;
4use serde_json::Value;
5use std::collections::HashMap;
6
7pub struct RequestUtils;
9
10impl RequestUtils {
11 pub fn build_query_string(params: &HashMap<String, Value>) -> String {
13 if params.is_empty() {
14 return String::new();
15 }
16
17 let pairs: Vec<String> = params
18 .iter()
19 .map(|(k, v)| {
20 let value_str = match v {
21 Value::String(s) => s.clone(),
22 Value::Number(n) => n.to_string(),
23 Value::Bool(b) => b.to_string(),
24 _ => v.to_string(),
25 };
26 format!("{}={}", k, urlencoding::encode(&value_str))
27 })
28 .collect();
29
30 pairs.join("&")
31 }
32
33 pub fn parse_json(response: &str) -> Result<Value, Error> {
35 serde_json::from_str(response).map_err(|e| Error::invalid_request(e.to_string()))
36 }
37
38 pub fn handle_http_error(status_code: u16, response: &str) -> Error {
40 match status_code {
41 400 => Error::invalid_request(response.to_string()),
42 401 | 403 => Error::authentication(response.to_string()),
43 404 => Error::invalid_request(format!("Endpoint not found: {response}")),
44 429 => Error::rate_limit(response.to_string(), None),
45 500..=599 => Error::exchange(status_code.to_string(), response),
46 _ => Error::network(format!("HTTP {status_code}: {response}")),
47 }
48 }
49
50 pub fn safe_string(dict: &Value, key: &str) -> Option<String> {
52 dict.get(key)
53 .and_then(|v| v.as_str())
54 .map(ToString::to_string)
55 }
56
57 pub fn safe_integer(dict: &Value, key: &str) -> Option<i64> {
59 dict.get(key).and_then(Value::as_i64)
60 }
61
62 pub fn safe_float(dict: &Value, key: &str) -> Option<f64> {
64 dict.get(key).and_then(Value::as_f64)
65 }
66
67 pub fn safe_bool(dict: &Value, key: &str) -> Option<bool> {
69 dict.get(key).and_then(Value::as_bool)
70 }
71}