Skip to main content

nautilus_bybit/http/
parse.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 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 serde::de::DeserializeOwned;
19
20use super::models::{
21    BybitInstrumentInverseResponse, BybitInstrumentLinearResponse, BybitInstrumentOptionResponse,
22    BybitInstrumentSpotResponse, BybitKlinesResponse, BybitServerTimeResponse,
23    BybitTickersLinearResponse, BybitTickersOptionResponse, BybitTickersSpotResponse,
24    BybitTradesResponse,
25};
26use crate::common::models::BybitResponse;
27
28fn parse_response<T: DeserializeOwned>(data: &[u8]) -> anyhow::Result<BybitResponse<T>> {
29    let response = serde_json::from_slice::<BybitResponse<T>>(data)?;
30    if response.ret_code != 0 {
31        anyhow::bail!(
32            "Bybit API error {}: {}",
33            response.ret_code,
34            response.ret_msg
35        );
36    }
37    Ok(response)
38}
39
40/// Parses a Bybit server time response from raw JSON bytes.
41///
42/// # Errors
43///
44/// Returns an error if deserialization or validation fails.
45pub fn parse_server_time_response(data: &[u8]) -> anyhow::Result<BybitServerTimeResponse> {
46    parse_response(data)
47}
48
49/// Parses a Bybit spot instruments response from raw JSON bytes.
50///
51/// # Errors
52///
53/// Returns an error if deserialization or validation fails.
54pub fn parse_instruments_spot_response(data: &[u8]) -> anyhow::Result<BybitInstrumentSpotResponse> {
55    parse_response(data)
56}
57
58/// Parses a Bybit linear instruments response from raw JSON bytes.
59///
60/// # Errors
61///
62/// Returns an error if deserialization or validation fails.
63pub fn parse_instruments_linear_response(
64    data: &[u8],
65) -> anyhow::Result<BybitInstrumentLinearResponse> {
66    parse_response(data)
67}
68
69/// Parses a Bybit inverse instruments response from raw JSON bytes.
70///
71/// # Errors
72///
73/// Returns an error if deserialization or validation fails.
74pub fn parse_instruments_inverse_response(
75    data: &[u8],
76) -> anyhow::Result<BybitInstrumentInverseResponse> {
77    parse_response(data)
78}
79
80/// Parses a Bybit option instruments response from raw JSON bytes.
81///
82/// # Errors
83///
84/// Returns an error if deserialization or validation fails.
85pub fn parse_instruments_option_response(
86    data: &[u8],
87) -> anyhow::Result<BybitInstrumentOptionResponse> {
88    parse_response(data)
89}
90
91/// Parses a Bybit spot tickers response from raw JSON bytes.
92///
93/// # Errors
94///
95/// Returns an error if deserialization or validation fails.
96pub fn parse_tickers_spot_response(data: &[u8]) -> anyhow::Result<BybitTickersSpotResponse> {
97    parse_response(data)
98}
99
100/// Parses a Bybit linear tickers response from raw JSON bytes.
101///
102/// # Errors
103///
104/// Returns an error if deserialization or validation fails.
105pub fn parse_tickers_linear_response(data: &[u8]) -> anyhow::Result<BybitTickersLinearResponse> {
106    parse_response(data)
107}
108
109/// Parses a Bybit option tickers response from raw JSON bytes.
110///
111/// # Errors
112///
113/// Returns an error if deserialization or validation fails.
114pub fn parse_tickers_option_response(data: &[u8]) -> anyhow::Result<BybitTickersOptionResponse> {
115    parse_response(data)
116}
117
118/// Parses a Bybit klines response from raw JSON bytes.
119///
120/// # Errors
121///
122/// Returns an error if deserialization or validation fails.
123pub fn parse_klines_response(data: &[u8]) -> anyhow::Result<BybitKlinesResponse> {
124    parse_response(data)
125}
126
127/// Parses a Bybit trades response from raw JSON bytes.
128///
129/// # Errors
130///
131/// Returns an error if deserialization or validation fails.
132pub fn parse_trades_response(data: &[u8]) -> anyhow::Result<BybitTradesResponse> {
133    parse_response(data)
134}
135
136#[cfg(test)]
137mod tests {
138    use rstest::rstest;
139
140    use super::*;
141    use crate::common::testing::load_test_json;
142
143    #[rstest]
144    fn test_parse_instruments_linear_response() {
145        let json = load_test_json("http_get_instruments_linear.json");
146        let result = parse_instruments_linear_response(json.as_bytes());
147        assert!(result.is_ok());
148
149        let response = result.unwrap();
150        assert_eq!(response.ret_code, 0);
151        assert!(!response.result.list.is_empty());
152    }
153
154    #[rstest]
155    fn test_parse_instruments_spot_response() {
156        let json = load_test_json("http_get_instruments_spot.json");
157        let result = parse_instruments_spot_response(json.as_bytes());
158        assert!(result.is_ok());
159
160        let response = result.unwrap();
161        assert_eq!(response.ret_code, 0);
162        assert!(!response.result.list.is_empty());
163    }
164
165    #[rstest]
166    fn test_parse_instruments_inverse_response() {
167        let json = load_test_json("http_get_instruments_inverse.json");
168        let result = parse_instruments_inverse_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_option_response() {
178        let json = load_test_json("http_get_instruments_option.json");
179        let result = parse_instruments_option_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_klines_response() {
189        let json = load_test_json("http_get_klines_linear.json");
190        let result = parse_klines_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_trades_response() {
200        let json = load_test_json("http_get_trades_recent.json");
201        let result = parse_trades_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}