bybit_rust_api/rest/
client.rs1use crate::consts::{
2 API_REQUEST_KEY, RECV_WINDOW_KEY, SIGNATURE_KEY, SIGN_TYPE_KEY, TIMESTAMP_KEY,
3};
4use crate::rest::api_key_pair::ApiKeyPair;
5use crate::rest::errors::{BybitResult, ErrorCodes};
6use crate::utils::{millis, sign};
7use reqwest::RequestBuilder;
8use serde::de::DeserializeOwned;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum SecType {
13 None = 0,
14 Signed = 1,
15}
16
17#[derive(Clone)]
18pub struct RestClient {
19 api_key_pair: ApiKeyPair,
20 base_url: String,
21
22 http_client: reqwest::Client,
23 recv_window: String,
24}
25
26#[derive(Serialize, Deserialize, Debug, Clone)]
27pub struct ServerResponse<T> {
28 #[serde(rename = "retCode")]
29 pub ret_code: i32,
30 #[serde(rename = "retMsg")]
31 pub ret_msg: String,
32 #[serde(rename = "result")]
33 pub result: T,
34 #[serde(rename = "retExtInfo")]
35 pub ret_ext_info: serde_json::Value,
36 #[serde(rename = "time")]
37 pub time: i64,
38}
39
40#[derive(Serialize, Deserialize, Debug, Clone)]
41struct RawServerResponse {
42 #[serde(rename = "retCode")]
43 pub ret_code: i32,
44 #[serde(rename = "retMsg")]
45 pub ret_msg: String,
46 #[serde(rename = "result")]
47 pub result: serde_json::Value,
48 #[serde(rename = "retExtInfo")]
49 pub ret_ext_info: serde_json::Value,
50 #[serde(rename = "time")]
51 pub time: i64,
52}
53
54impl RestClient {
55 pub fn new(api_key_pair: ApiKeyPair, base_url: String) -> RestClient {
56 RestClient {
57 api_key_pair,
58 base_url,
59 http_client: reqwest::Client::new(),
60 recv_window: "5000".to_string(),
61 }
62 }
63
64 pub fn with_recv_window(mut self, recv_window: impl Into<String>) -> Self {
65 self.recv_window = recv_window.into();
66 self
67 }
68
69 fn query_string(&self, query: serde_json::Value) -> BybitResult<String> {
70 let object = query.as_object().ok_or_else(|| {
71 crate::rest::errors::BybitError::Internal(
72 "Query params must be a JSON object".to_string(),
73 )
74 })?;
75 Ok(serde_urlencoded::to_string(object)?)
76 }
77
78 fn sign_request(
79 &self,
80 request_builder: RequestBuilder,
81 query_or_body_param: String,
82 ) -> RequestBuilder {
83 let recv_window = &self.recv_window;
84 let timestamp_str = millis().to_string();
85 let signature = sign(
86 &self.api_key_pair.secret(),
87 &format!(
88 "{}{}{}{}",
89 timestamp_str,
90 self.api_key_pair.key(),
91 recv_window,
92 query_or_body_param
93 ),
94 );
95
96 request_builder
97 .header(SIGN_TYPE_KEY, "2")
98 .header(API_REQUEST_KEY, self.api_key_pair.key())
99 .header(TIMESTAMP_KEY, timestamp_str)
100 .header(RECV_WINDOW_KEY, recv_window)
101 .header(SIGNATURE_KEY, signature)
102 }
103
104 pub async fn get<A: DeserializeOwned>(
105 &self,
106 endpoint: &str,
107 query: serde_json::Value,
108 sec_type: SecType,
109 ) -> BybitResult<ServerResponse<A>> {
110 let mut url = format!("{}/{}", self.base_url, endpoint);
111 let query_string = self.query_string(query)?;
112
113 if !query_string.is_empty() {
114 url.push_str(&format!("?{}", query_string));
115 }
116
117 let mut request_builder = self.http_client.get(&url);
118 if sec_type == SecType::Signed {
119 request_builder = self.sign_request(request_builder, query_string);
120 }
121
122 log::debug!("url: {}", url);
123
124 let r = request_builder.send().await?;
125 let raw_response: RawServerResponse = r.json().await?;
126
127 if raw_response.ret_code != 0 {
128 let code_str = raw_response.ret_code.to_string();
129 if let Ok(error_code) = serde_json::from_value(serde_json::json!(code_str)) {
131 return Err(crate::rest::errors::BybitError::Api(error_code));
132 } else {
133 return Err(crate::rest::errors::BybitError::Api(
134 crate::rest::errors::ErrorCodes::E10001,
135 )); }
137 }
138
139 let result: A = serde_json::from_value(raw_response.result)?;
140 Ok(ServerResponse {
141 ret_code: raw_response.ret_code,
142 ret_msg: raw_response.ret_msg,
143 result,
144 ret_ext_info: raw_response.ret_ext_info,
145 time: raw_response.time,
146 })
147 }
148
149 pub async fn post<A: DeserializeOwned>(
150 &self,
151 endpoint: &str,
152 body: serde_json::Value,
153 sec_type: SecType,
154 ) -> BybitResult<ServerResponse<A>> {
155 let url = format!("{}/{}", self.base_url, endpoint);
156 let mut request_builder = self.http_client.post(&url);
157 if sec_type == SecType::Signed {
158 let body_str =
159 serde_json::to_string(&body).map_err(crate::rest::errors::BybitError::Json)?;
160 request_builder = self.sign_request(request_builder, body_str);
161 }
162
163 let r = request_builder.json(&body).send().await?;
164 let raw_response: RawServerResponse = r.json().await?;
165
166 if raw_response.ret_code != 0 {
167 let code_str = raw_response.ret_code.to_string();
168 if let Ok(error_code) = serde_json::from_value(serde_json::json!(code_str)) {
169 return Err(crate::rest::errors::BybitError::Api(error_code));
170 } else {
171 return Err(crate::rest::errors::BybitError::Api(ErrorCodes::E10001));
172 }
173 }
174
175 let result: A = serde_json::from_value(raw_response.result)?;
176 Ok(ServerResponse {
177 ret_code: raw_response.ret_code,
178 ret_msg: raw_response.ret_msg,
179 result,
180 ret_ext_info: raw_response.ret_ext_info,
181 time: raw_response.time,
182 })
183 }
184}