boj_client/client/
core.rs1use crate::decode::{decode_code, decode_layer, decode_metadata};
2use crate::error::BojError;
3use crate::model::{CodeResponse, LayerResponse, MetadataResponse};
4use crate::query::{CodeQuery, LayerQuery, MetadataQuery};
5use crate::transport::ReqwestTransport;
6
7use super::http::{execute_request, header_value};
8use super::response::{ensure_success_status, normalize_response_body};
9
10const DEFAULT_BASE_URL: &str = "https://www.stat-search.boj.or.jp";
11
12pub struct BojClient {
34 transport: ReqwestTransport,
35 base_url: String,
36}
37
38impl Default for BojClient {
39 fn default() -> Self {
40 Self::new()
41 }
42}
43
44impl BojClient {
45 pub fn new() -> Self {
47 Self {
48 transport: ReqwestTransport::default(),
49 base_url: DEFAULT_BASE_URL.to_string(),
50 }
51 }
52
53 pub fn with_reqwest_client(client: reqwest::blocking::Client) -> Self {
58 Self {
59 transport: ReqwestTransport::new(client),
60 base_url: DEFAULT_BASE_URL.to_string(),
61 }
62 }
63
64 pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
68 self.base_url = base_url.into();
69 self
70 }
71
72 pub fn get_data_code(&self, query: &CodeQuery) -> Result<CodeResponse, BojError> {
79 let response = execute_request(
80 &self.transport,
81 &self.base_url,
82 query.endpoint(),
83 query.query_pairs(),
84 )?;
85
86 let content_type = header_value(&response, "content-type");
87 let body = normalize_response_body(&response)?;
88 let decoded = decode_code(&body, content_type.as_deref(), query.csv_encoding_hint())?;
89
90 ensure_success_status(
91 decoded.meta.status,
92 &decoded.meta.message_id,
93 &decoded.meta.message,
94 )?;
95
96 Ok(decoded)
97 }
98
99 pub fn get_data_layer(&self, query: &LayerQuery) -> Result<LayerResponse, BojError> {
106 let response = execute_request(
107 &self.transport,
108 &self.base_url,
109 query.endpoint(),
110 query.query_pairs(),
111 )?;
112
113 let content_type = header_value(&response, "content-type");
114 let body = normalize_response_body(&response)?;
115 let decoded = decode_layer(&body, content_type.as_deref(), query.csv_encoding_hint())?;
116
117 ensure_success_status(
118 decoded.meta.status,
119 &decoded.meta.message_id,
120 &decoded.meta.message,
121 )?;
122
123 Ok(decoded)
124 }
125
126 pub fn get_metadata(&self, query: &MetadataQuery) -> Result<MetadataResponse, BojError> {
133 let response = execute_request(
134 &self.transport,
135 &self.base_url,
136 query.endpoint(),
137 query.query_pairs(),
138 )?;
139
140 let content_type = header_value(&response, "content-type");
141 let body = normalize_response_body(&response)?;
142 let decoded = decode_metadata(&body, content_type.as_deref(), query.csv_encoding_hint())?;
143
144 ensure_success_status(
145 decoded.meta.status,
146 &decoded.meta.message_id,
147 &decoded.meta.message,
148 )?;
149
150 Ok(decoded)
151 }
152}