Skip to main content

cbr_client/
client_common.rs

1/// Базовый URL API ЦБ РФ.
2pub const DEFAULT_BASE_URL: &str = "https://www.cbr.ru/dataservice";
3
4pub(crate) fn normalize_base_url(base_url: impl AsRef<str>) -> String {
5    let value = base_url.as_ref().trim();
6    if value.is_empty() {
7        DEFAULT_BASE_URL.to_owned()
8    } else {
9        value.trim_end_matches('/').to_owned()
10    }
11}
12
13pub(crate) fn endpoint(base_url: &str, path: &str) -> String {
14    format!("{}/{}", base_url, path.trim_start_matches('/'))
15}
16
17macro_rules! configure_reqwest_builder {
18    (
19        $builder:expr,
20        timeout = $timeout:expr,
21        use_system_proxy = $use_system_proxy:expr,
22        proxy_url = $proxy_url:expr,
23        user_agent = $user_agent:expr
24    ) => {{
25        let mut builder = $builder.timeout($timeout).http1_only();
26
27        if !$use_system_proxy && $proxy_url.is_none() {
28            builder = builder.no_proxy();
29        }
30
31        if let Some(proxy_url) = $proxy_url {
32            let proxy = reqwest::Proxy::all(proxy_url).map_err(crate::error::CbrError::build)?;
33            builder = builder.proxy(proxy);
34        }
35
36        if let Some(user_agent) = $user_agent {
37            builder = builder.user_agent(user_agent);
38        }
39
40        builder
41    }};
42}
43
44macro_rules! cbr_endpoint_methods {
45    ($impl_macro:ident) => {
46        $impl_macro!(
47            "Возвращает список публикаций (`/publications`).",
48            publications,
49            (),
50            Vec<Publication>,
51            "/publications",
52            no_query
53        );
54        $impl_macro!(
55            "Возвращает список показателей публикации (`/datasets`).",
56            datasets,
57            (publication_id: PublicationId),
58            Vec<Dataset>,
59            "/datasets",
60            query(publication_id_query(publication_id))
61        );
62        $impl_macro!(
63            "Возвращает разрезы показателя (`/measures`).",
64            measures,
65            (dataset_id: DatasetId),
66            MeasuresResponse,
67            "/measures",
68            query(dataset_id_query(dataset_id))
69        );
70        $impl_macro!(
71            "Возвращает доступный диапазон годов (`/years`).",
72            years,
73            (dataset_id: DatasetId, measure_id: Option<MeasureId>),
74            Vec<YearRange>,
75            "/years",
76            query(years_query(dataset_id, measure_id))
77        );
78        $impl_macro!(
79            "Возвращает диапазон годов в расширенном формате (`/yearsEx`).",
80            years_ex,
81            (publication_id: PublicationId, ids: &[DatasetId]),
82            Vec<YearRange>,
83            "/yearsEx",
84            query(years_ex_query(publication_id, ids))
85        );
86        $impl_macro!(
87            "Возвращает показатели и разрезы публикации (`/datasetsEx`).",
88            datasets_ex,
89            (publication_id: PublicationId),
90            DatasetsExResponse,
91            "/datasetsEx",
92            query(publication_id_query(publication_id))
93        );
94        $impl_macro!(
95            "Возвращает данные для таблицы (`/data`).",
96            data,
97            (query: DataQuery),
98            DataResponse,
99            "/data",
100            query(query)
101        );
102        $impl_macro!(
103            "Возвращает данные в расширенном формате (`/dataEx`).",
104            data_ex,
105            (query: DataExQuery),
106            DataExResponse,
107            "/dataEx",
108            query(query)
109        );
110        $impl_macro!(
111            "Возвращает описание (методологию) показателя (`/DatasetDescription`).",
112            dataset_description,
113            (dataset_id: DatasetId),
114            Vec<DatasetDescription>,
115            "/DatasetDescription",
116            query(dataset_id_query(dataset_id))
117        );
118        $impl_macro!(
119            "Возвращает список категорий и показателей (`/categoryNew`).",
120            category_new,
121            (),
122            CategoryNewResponse,
123            "/categoryNew",
124            no_query
125        );
126        $impl_macro!(
127            "Возвращает данные показателей (`/dataNew`).",
128            data_new,
129            (query: DataNewQuery),
130            DataNewResponse,
131            "/dataNew",
132            query(query)
133        );
134    };
135}
136
137pub(crate) use cbr_endpoint_methods;
138pub(crate) use configure_reqwest_builder;
139
140#[cfg(test)]
141mod tests {
142    use super::{DEFAULT_BASE_URL, endpoint, normalize_base_url};
143
144    #[test]
145    fn normalize_base_url_uses_default_for_empty_value() {
146        assert_eq!(normalize_base_url("  "), DEFAULT_BASE_URL);
147    }
148
149    #[test]
150    fn normalize_base_url_trims_trailing_slashes() {
151        assert_eq!(
152            normalize_base_url("https://example.com/api///"),
153            "https://example.com/api"
154        );
155    }
156
157    #[test]
158    fn endpoint_trims_leading_slashes_in_path() {
159        assert_eq!(
160            endpoint("https://example.com/api", "//datasets"),
161            "https://example.com/api/datasets"
162        );
163    }
164}