pub const DEFAULT_BASE_URL: &str = "https://www.cbr.ru/dataservice";
pub(crate) fn normalize_base_url(base_url: impl AsRef<str>) -> String {
let value = base_url.as_ref().trim();
if value.is_empty() {
DEFAULT_BASE_URL.to_owned()
} else {
value.trim_end_matches('/').to_owned()
}
}
pub(crate) fn endpoint(base_url: &str, path: &str) -> String {
format!("{}/{}", base_url, path.trim_start_matches('/'))
}
macro_rules! configure_reqwest_builder {
(
$builder:expr,
timeout = $timeout:expr,
use_system_proxy = $use_system_proxy:expr,
proxy_url = $proxy_url:expr,
user_agent = $user_agent:expr
) => {{
let mut builder = $builder.timeout($timeout).http1_only();
if !$use_system_proxy && $proxy_url.is_none() {
builder = builder.no_proxy();
}
if let Some(proxy_url) = $proxy_url {
let proxy = reqwest::Proxy::all(proxy_url).map_err(crate::error::CbrError::build)?;
builder = builder.proxy(proxy);
}
if let Some(user_agent) = $user_agent {
builder = builder.user_agent(user_agent);
}
builder
}};
}
macro_rules! cbr_endpoint_methods {
($impl_macro:ident) => {
$impl_macro!(
"Возвращает список публикаций (`/publications`).",
publications,
(),
Vec<Publication>,
"/publications",
no_query
);
$impl_macro!(
"Возвращает список показателей публикации (`/datasets`).",
datasets,
(publication_id: PublicationId),
Vec<Dataset>,
"/datasets",
query(publication_id_query(publication_id))
);
$impl_macro!(
"Возвращает разрезы показателя (`/measures`).",
measures,
(dataset_id: DatasetId),
MeasuresResponse,
"/measures",
query(dataset_id_query(dataset_id))
);
$impl_macro!(
"Возвращает доступный диапазон годов (`/years`).",
years,
(dataset_id: DatasetId, measure_id: Option<MeasureId>),
Vec<YearRange>,
"/years",
query(years_query(dataset_id, measure_id))
);
$impl_macro!(
"Возвращает диапазон годов в расширенном формате (`/yearsEx`).",
years_ex,
(publication_id: PublicationId, ids: &[DatasetId]),
Vec<YearRange>,
"/yearsEx",
query(years_ex_query(publication_id, ids))
);
$impl_macro!(
"Возвращает показатели и разрезы публикации (`/datasetsEx`).",
datasets_ex,
(publication_id: PublicationId),
DatasetsExResponse,
"/datasetsEx",
query(publication_id_query(publication_id))
);
$impl_macro!(
"Возвращает данные для таблицы (`/data`).",
data,
(query: DataQuery),
DataResponse,
"/data",
query(query)
);
$impl_macro!(
"Возвращает данные в расширенном формате (`/dataEx`).",
data_ex,
(query: DataExQuery),
DataExResponse,
"/dataEx",
query(query)
);
$impl_macro!(
"Возвращает описание (методологию) показателя (`/DatasetDescription`).",
dataset_description,
(dataset_id: DatasetId),
Vec<DatasetDescription>,
"/DatasetDescription",
query(dataset_id_query(dataset_id))
);
$impl_macro!(
"Возвращает список категорий и показателей (`/categoryNew`).",
category_new,
(),
CategoryNewResponse,
"/categoryNew",
no_query
);
$impl_macro!(
"Возвращает данные показателей (`/dataNew`).",
data_new,
(query: DataNewQuery),
DataNewResponse,
"/dataNew",
query(query)
);
};
}
pub(crate) use cbr_endpoint_methods;
pub(crate) use configure_reqwest_builder;
#[cfg(test)]
mod tests {
use super::{DEFAULT_BASE_URL, endpoint, normalize_base_url};
#[test]
fn normalize_base_url_uses_default_for_empty_value() {
assert_eq!(normalize_base_url(" "), DEFAULT_BASE_URL);
}
#[test]
fn normalize_base_url_trims_trailing_slashes() {
assert_eq!(
normalize_base_url("https://example.com/api///"),
"https://example.com/api"
);
}
#[test]
fn endpoint_trims_leading_slashes_in_path() {
assert_eq!(
endpoint("https://example.com/api", "//datasets"),
"https://example.com/api/datasets"
);
}
}