dceapi_rs/client.rs
1//! DCE API client.
2//!
3//! The main entry point for using the DCE API.
4
5use std::sync::Arc;
6
7use reqwest::Client as HttpClient;
8
9use crate::config::Config;
10use crate::error::{Error, Result};
11use crate::http::BaseClient;
12use crate::services::{
13 CommonService, DeliveryService, MarketService, MemberService, NewsService, SettleService,
14 TradeService,
15};
16use crate::token::TokenManager;
17
18/// DCE API client.
19///
20/// This is the main entry point for using the DCE API. It provides access to all
21/// API services through dedicated service instances.
22///
23/// # Example
24///
25/// ```no_run
26/// use dceapi::{Client, Config};
27///
28/// #[tokio::main]
29/// async fn main() -> dceapi::Result<()> {
30/// let config = Config::new()
31/// .with_api_key("your-api-key")
32/// .with_secret("your-secret");
33///
34/// let client = Client::new(config)?;
35///
36/// // Get current trade date
37/// let trade_date = client.common.get_curr_trade_date(None).await?;
38/// println!("Trade date: {}", trade_date.date);
39///
40/// Ok(())
41/// }
42/// ```
43#[derive(Debug, Clone)]
44pub struct Client {
45 config: Arc<Config>,
46 token_manager: Arc<TokenManager>,
47
48 /// News service for articles and announcements.
49 pub news: NewsService,
50
51 /// Common service for trade dates and varieties.
52 pub common: CommonService,
53
54 /// Market service for quotes and market data.
55 pub market: MarketService,
56
57 /// Delivery service for delivery data.
58 pub delivery: DeliveryService,
59
60 /// Member service for member rankings.
61 pub member: MemberService,
62
63 /// Trade service for trading parameters.
64 pub trade: TradeService,
65
66 /// Settlement service for settlement parameters.
67 pub settle: SettleService,
68}
69
70impl Client {
71 /// Create a new DCE API client.
72 ///
73 /// # Arguments
74 /// * `config` - Client configuration with API credentials
75 ///
76 /// # Errors
77 /// Returns an error if the configuration is invalid (missing API key or secret).
78 ///
79 /// # Example
80 ///
81 /// ```no_run
82 /// use dceapi::{Client, Config};
83 ///
84 /// let config = Config::new()
85 /// .with_api_key("your-api-key")
86 /// .with_secret("your-secret");
87 ///
88 /// let client = Client::new(config).expect("Failed to create client");
89 /// ```
90 pub fn new(mut config: Config) -> Result<Self> {
91 // Apply defaults
92 config.apply_defaults();
93
94 // Validate configuration
95 config.validate()?;
96
97 // Create HTTP client
98 let http_client = HttpClient::builder()
99 .timeout(config.timeout)
100 .gzip(true)
101 .brotli(true)
102 .deflate(true)
103 .build()
104 .map_err(|e| {
105 Error::validation(
106 "http_client",
107 format!("failed to create HTTP client: {}", e),
108 )
109 })?;
110
111 // Create token manager
112 let token_manager = Arc::new(TokenManager::new(
113 &config.api_key,
114 &config.secret,
115 &config.base_url,
116 http_client.clone(),
117 ));
118
119 // Create base client
120 let base_client = BaseClient::new(config.clone(), http_client, token_manager.clone());
121
122 // Create client with all services
123 Ok(Client {
124 config: Arc::new(config),
125 token_manager,
126 news: NewsService::new(base_client.clone()),
127 common: CommonService::new(base_client.clone()),
128 market: MarketService::new(base_client.clone()),
129 delivery: DeliveryService::new(base_client.clone()),
130 member: MemberService::new(base_client.clone()),
131 trade: TradeService::new(base_client.clone()),
132 settle: SettleService::new(base_client),
133 })
134 }
135
136 /// Create a new client from environment variables.
137 ///
138 /// Reads `DCE_API_KEY` and `DCE_SECRET` from the environment.
139 ///
140 /// # Errors
141 /// Returns an error if the environment variables are not set.
142 pub fn from_env() -> Result<Self> {
143 let config = Config::from_env();
144 Self::new(config)
145 }
146
147 /// Get the client configuration (read-only).
148 pub fn config(&self) -> &Config {
149 &self.config
150 }
151
152 /// Get the token manager.
153 ///
154 /// This can be used for advanced token management, such as forcing a refresh.
155 pub fn token_manager(&self) -> &TokenManager {
156 &self.token_manager
157 }
158}