nautilus_bybit/http/
parse.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Parsing functions for Bybit HTTP API responses.
17
18use super::models::{
19    BybitInstrumentInverseResponse, BybitInstrumentLinearResponse, BybitInstrumentOptionResponse,
20    BybitInstrumentSpotResponse, BybitKlinesResponse, BybitServerTimeResponse,
21    BybitTickersLinearResponse, BybitTickersOptionResponse, BybitTickersSpotResponse,
22    BybitTradesResponse,
23};
24use crate::common::models::BybitResponse;
25
26/// Parses a Bybit server time response from raw JSON bytes.
27///
28/// # Errors
29///
30/// Returns an error if deserialization fails.
31pub fn parse_server_time_response(data: &[u8]) -> anyhow::Result<BybitServerTimeResponse> {
32    let response = serde_json::from_slice::<BybitServerTimeResponse>(data)?;
33    validate_response(&response)?;
34    Ok(response)
35}
36
37/// Parses a Bybit spot instruments response from raw JSON bytes.
38///
39/// # Errors
40///
41/// Returns an error if deserialization fails.
42pub fn parse_instruments_spot_response(data: &[u8]) -> anyhow::Result<BybitInstrumentSpotResponse> {
43    let response = serde_json::from_slice::<BybitInstrumentSpotResponse>(data)?;
44    validate_response(&response)?;
45    Ok(response)
46}
47
48/// Parses a Bybit linear instruments response from raw JSON bytes.
49///
50/// # Errors
51///
52/// Returns an error if deserialization fails.
53pub fn parse_instruments_linear_response(
54    data: &[u8],
55) -> anyhow::Result<BybitInstrumentLinearResponse> {
56    let response = serde_json::from_slice::<BybitInstrumentLinearResponse>(data)?;
57    validate_response(&response)?;
58    Ok(response)
59}
60
61/// Parses a Bybit inverse instruments response from raw JSON bytes.
62///
63/// # Errors
64///
65/// Returns an error if deserialization fails.
66pub fn parse_instruments_inverse_response(
67    data: &[u8],
68) -> anyhow::Result<BybitInstrumentInverseResponse> {
69    let response = serde_json::from_slice::<BybitInstrumentInverseResponse>(data)?;
70    validate_response(&response)?;
71    Ok(response)
72}
73
74/// Parses a Bybit option instruments response from raw JSON bytes.
75///
76/// # Errors
77///
78/// Returns an error if deserialization fails.
79pub fn parse_instruments_option_response(
80    data: &[u8],
81) -> anyhow::Result<BybitInstrumentOptionResponse> {
82    let response = serde_json::from_slice::<BybitInstrumentOptionResponse>(data)?;
83    validate_response(&response)?;
84    Ok(response)
85}
86
87/// Parses a Bybit spot tickers response from raw JSON bytes.
88///
89/// # Errors
90///
91/// Returns an error if deserialization fails.
92pub fn parse_tickers_spot_response(data: &[u8]) -> anyhow::Result<BybitTickersSpotResponse> {
93    let response = serde_json::from_slice::<BybitTickersSpotResponse>(data)?;
94    validate_response(&response)?;
95    Ok(response)
96}
97
98/// Parses a Bybit linear tickers response from raw JSON bytes.
99///
100/// # Errors
101///
102/// Returns an error if deserialization fails.
103pub fn parse_tickers_linear_response(data: &[u8]) -> anyhow::Result<BybitTickersLinearResponse> {
104    let response = serde_json::from_slice::<BybitTickersLinearResponse>(data)?;
105    validate_response(&response)?;
106    Ok(response)
107}
108
109/// Parses a Bybit option tickers response from raw JSON bytes.
110///
111/// # Errors
112///
113/// Returns an error if deserialization fails.
114pub fn parse_tickers_option_response(data: &[u8]) -> anyhow::Result<BybitTickersOptionResponse> {
115    let response = serde_json::from_slice::<BybitTickersOptionResponse>(data)?;
116    validate_response(&response)?;
117    Ok(response)
118}
119
120/// Parses a Bybit klines response from raw JSON bytes.
121///
122/// # Errors
123///
124/// Returns an error if deserialization fails.
125pub fn parse_klines_response(data: &[u8]) -> anyhow::Result<BybitKlinesResponse> {
126    let response = serde_json::from_slice::<BybitKlinesResponse>(data)?;
127    validate_response(&response)?;
128    Ok(response)
129}
130
131/// Parses a Bybit trades response from raw JSON bytes.
132///
133/// # Errors
134///
135/// Returns an error if deserialization fails.
136pub fn parse_trades_response(data: &[u8]) -> anyhow::Result<BybitTradesResponse> {
137    let response = serde_json::from_slice::<BybitTradesResponse>(data)?;
138    validate_response(&response)?;
139    Ok(response)
140}
141
142/// Validates that a Bybit response has a successful return code.
143///
144/// # Errors
145///
146/// Returns an error if the response indicates a failure.
147fn validate_response<T>(response: &BybitResponse<T>) -> anyhow::Result<()> {
148    if response.ret_code != 0 {
149        anyhow::bail!(
150            "Bybit API error {}: {}",
151            response.ret_code,
152            response.ret_msg
153        );
154    }
155    Ok(())
156}
157
158#[cfg(test)]
159mod tests {
160    use rstest::rstest;
161
162    use super::*;
163    use crate::common::testing::load_test_json;
164
165    #[rstest]
166    fn test_parse_instruments_linear_response() {
167        let json = load_test_json("http_get_instruments_linear.json");
168        let result = parse_instruments_linear_response(json.as_bytes());
169        assert!(result.is_ok());
170
171        let response = result.unwrap();
172        assert_eq!(response.ret_code, 0);
173        assert!(!response.result.list.is_empty());
174    }
175
176    #[rstest]
177    fn test_parse_instruments_spot_response() {
178        let json = load_test_json("http_get_instruments_spot.json");
179        let result = parse_instruments_spot_response(json.as_bytes());
180        assert!(result.is_ok());
181
182        let response = result.unwrap();
183        assert_eq!(response.ret_code, 0);
184        assert!(!response.result.list.is_empty());
185    }
186
187    #[rstest]
188    fn test_parse_instruments_inverse_response() {
189        let json = load_test_json("http_get_instruments_inverse.json");
190        let result = parse_instruments_inverse_response(json.as_bytes());
191        assert!(result.is_ok());
192
193        let response = result.unwrap();
194        assert_eq!(response.ret_code, 0);
195        assert!(!response.result.list.is_empty());
196    }
197
198    #[rstest]
199    fn test_parse_instruments_option_response() {
200        let json = load_test_json("http_get_instruments_option.json");
201        let result = parse_instruments_option_response(json.as_bytes());
202        assert!(result.is_ok());
203
204        let response = result.unwrap();
205        assert_eq!(response.ret_code, 0);
206        assert!(!response.result.list.is_empty());
207    }
208
209    #[rstest]
210    fn test_parse_klines_response() {
211        let json = load_test_json("http_get_klines_linear.json");
212        let result = parse_klines_response(json.as_bytes());
213        assert!(result.is_ok());
214
215        let response = result.unwrap();
216        assert_eq!(response.ret_code, 0);
217        assert!(!response.result.list.is_empty());
218    }
219
220    #[rstest]
221    fn test_parse_trades_response() {
222        let json = load_test_json("http_get_trades_recent.json");
223        let result = parse_trades_response(json.as_bytes());
224        assert!(result.is_ok());
225
226        let response = result.unwrap();
227        assert_eq!(response.ret_code, 0);
228        assert!(!response.result.list.is_empty());
229    }
230}