tushare_api/
lib.rs

1//! # Tushare API Client Library
2//!
3//! A comprehensive Rust client library for accessing Tushare financial data APIs.
4//! This library provides a simple and efficient way to fetch financial data from Tushare,
5//! with built-in support for request/response handling, error management, and logging.
6//!
7//! ## Features
8//!
9//! - **Easy-to-use API**: Simple client interface for making Tushare API calls
10//! - **Type Safety**: Strong typing for requests and responses
11//! - **Error Handling**: Comprehensive error types and handling
12//! - **Logging Support**: Built-in logging with configurable levels
13//! - **Async Support**: Full async/await support with tokio
14//! - **Flexible Configuration**: Customizable HTTP client settings
15//! - **Environment Integration**: Automatic token loading from environment variables
16//! - **Automatic Conversion**: Derive macros for automatic struct conversion from API responses
17//!
18//! ## Quick Start
19//!
20//! ```no_run
21//! use tushare_api::{TushareClient, Api, TushareRequest, TushareEntityList, params, fields};
22//! use tushare_api::DeriveFromTushareData;
23//!
24//! // Define your data structure with derive macro
25//! #[derive(Debug, Clone, DeriveFromTushareData)]
26//! pub struct Stock {
27//!     ts_code: String,
28//!     symbol: String,
29//!     name: String,
30//!     area: Option<String>,
31//! }
32//!
33//! #[tokio::main]
34//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
35//!     // Create client from environment variable TUSHARE_TOKEN
36//!     let client = TushareClient::from_env()?;
37//!     
38//!     // Create request using manual construction
39//!     let request = TushareRequest::new(
40//!         Api::StockBasic,
41//!         params!("list_status" => "L"),
42//!         fields!["ts_code", "symbol", "name", "area"]
43//!     );
44//!     
45//!     // Make the API call with automatic conversion
46//!     let stocks: TushareEntityList<Stock> = client.call_api_as(request).await?;
47//!     
48//!     println!("Received {} stocks", stocks.len());
49//!     
50//!     for stock in stocks.iter().take(5) {
51//!         println!("{}: {}", stock.ts_code, stock.name);
52//!     }
53//!     
54//!     Ok(())
55//! }
56//! ```
57
58pub mod error;
59pub mod api;
60pub mod types;
61pub mod client;
62pub mod logging;
63pub mod traits;
64pub mod utils;
65pub mod basic_types;
66pub mod third_party_types;
67pub mod custom_date_format;
68
69// Re-export main types for convenience
70pub use error::{TushareError, TushareResult};
71pub use api::Api;
72pub use types::{TushareRequest, TushareResponse, TushareData, TushareEntityList};
73pub use client::{TushareClient, HttpClientConfig};
74pub use logging::{LogConfig, LogLevel, Logger};
75pub use traits::{FromTushareData, FromTushareValue, FromOptionalTushareValue};
76pub use utils::response_to_vec;
77
78// Macros are automatically exported at the crate root via #[macro_export]
79
80// Re-export procedural macros from tushare-derive
81pub use tushare_derive::{FromTushareData as DeriveFromTushareData};
82
83// Re-export serde_json for user convenience
84pub use serde_json;
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use crate::types::TushareData;
90    use serde_json::json;
91
92    #[test]
93    fn test_api_serialization() {
94        let api = Api::StockBasic;
95        assert_eq!(api.name(), "stock_basic");
96    }
97
98    #[test]
99    fn test_tushare_request_creation() {
100        let request = TushareRequest::new(
101            Api::StockBasic,
102            vec![("list_status".to_string(), "L".to_string())],
103            vec!["ts_code".to_string(), "symbol".to_string()]
104        );
105        
106        assert_eq!(request.api_name, Api::StockBasic);
107        assert_eq!(request.params.len(), 1);
108        assert_eq!(request.fields.len(), 2);
109    }
110
111    #[test]
112    fn test_tushare_response_creation() {
113        let response = TushareResponse {
114            request_id: "test123".to_string(),
115            code: 0,
116            msg: None,
117            data: Some(TushareData {
118                fields: vec!["ts_code".to_string(), "name".to_string()],
119                items: vec![
120                    vec![json!("000001.SZ"), json!("平安银行")],
121                    vec![json!("000002.SZ"), json!("万科A")],
122                ],
123                has_more: false,
124                count: 2,
125            }),
126        };
127        
128        assert_eq!(response.code, 0);
129        assert_eq!(response.data.map(|data| data.items.len()).unwrap_or(0), 2);
130        assert_eq!(response.data.map(|data| data.items.len()).unwrap_or(0), 2);
131    }
132}