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 BojClient {
39 pub fn new() -> Result<Self, BojError> {
49 let client = ReqwestTransport::build_default_client()?;
50 Ok(Self {
51 transport: ReqwestTransport::new(client),
52 base_url: DEFAULT_BASE_URL.to_string(),
53 })
54 }
55
56 pub fn with_reqwest_client(client: reqwest::blocking::Client) -> Self {
61 Self {
62 transport: ReqwestTransport::new(client),
63 base_url: DEFAULT_BASE_URL.to_string(),
64 }
65 }
66
67 pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
71 self.base_url = base_url.into();
72 self
73 }
74
75 pub fn get_data_code(&self, query: &CodeQuery) -> Result<CodeResponse, BojError> {
82 let response = execute_request(
83 &self.transport,
84 &self.base_url,
85 query.endpoint(),
86 query.query_pairs(),
87 )?;
88
89 let content_type = header_value(&response, "content-type");
90 let body = normalize_response_body(&response)?;
91 let decoded = decode_code(&body, content_type.as_deref(), query.csv_encoding_hint())?;
92
93 ensure_success_status(
94 decoded.meta.status,
95 &decoded.meta.message_id,
96 &decoded.meta.message,
97 )?;
98
99 Ok(decoded)
100 }
101
102 pub fn get_data_layer(&self, query: &LayerQuery) -> Result<LayerResponse, BojError> {
109 let response = execute_request(
110 &self.transport,
111 &self.base_url,
112 query.endpoint(),
113 query.query_pairs(),
114 )?;
115
116 let content_type = header_value(&response, "content-type");
117 let body = normalize_response_body(&response)?;
118 let decoded = decode_layer(&body, content_type.as_deref(), query.csv_encoding_hint())?;
119
120 ensure_success_status(
121 decoded.meta.status,
122 &decoded.meta.message_id,
123 &decoded.meta.message,
124 )?;
125
126 Ok(decoded)
127 }
128
129 pub fn get_metadata(&self, query: &MetadataQuery) -> Result<MetadataResponse, BojError> {
136 let response = execute_request(
137 &self.transport,
138 &self.base_url,
139 query.endpoint(),
140 query.query_pairs(),
141 )?;
142
143 let content_type = header_value(&response, "content-type");
144 let body = normalize_response_body(&response)?;
145 let decoded = decode_metadata(&body, content_type.as_deref(), query.csv_encoding_hint())?;
146
147 ensure_success_status(
148 decoded.meta.status,
149 &decoded.meta.message_id,
150 &decoded.meta.message,
151 )?;
152
153 Ok(decoded)
154 }
155}