pub mod error;
pub use error::Error;
mod result;
pub use result::Result;
mod servers;
pub use servers::Server;
use Error::InvalidBaseUrl;
use std::fmt;
use url::Url;
const AUTH_HEADER_KEY: &str = "X-API-Key";
#[derive(Clone, Debug)]
pub struct Client {
base_url: Url,
client: reqwest::blocking::Client,
}
impl fmt::Display for Client {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pdns client with base_url = {}", self.base_url)
}
}
impl Client {
pub fn new(base_url: impl AsRef<str>, api_key: &str) -> Result<Self> {
let client = get_internal_reqwest_client(api_key)?;
let base_url = pdns_api_url(base_url)?;
Ok(Client { base_url, client })
}
pub fn new_with_client(
base_url: impl AsRef<str>,
client: reqwest::blocking::Client,
) -> Result<Self> {
let base_url = pdns_api_url(base_url)?;
Ok(Client { base_url, client })
}
#[must_use = "this is a getter"]
pub fn base_url(&self) -> &url::Url {
&self.base_url
}
}
fn pdns_api_url(base_url: impl AsRef<str>) -> Result<Url> {
let base_url = Url::parse(base_url.as_ref())?;
let base_url = base_url.join("/api/v1/")?;
validate_base_url(&base_url)?;
Ok(base_url)
}
fn validate_base_url(base_url: &Url) -> Result<bool> {
if base_url.cannot_be_a_base() {
return Err(InvalidBaseUrl("scheme is regarded as non base url".into()));
}
if !matches!(base_url.scheme(), "http" | "https") {
return Err(InvalidBaseUrl("scheme must be one of http or https".into()));
}
Ok(true)
}
fn get_internal_reqwest_client(api_key: &str) -> Result<reqwest::blocking::Client> {
let mut headers = reqwest::header::HeaderMap::new();
let mut api_key = reqwest::header::HeaderValue::from_str(api_key)?;
api_key.set_sensitive(true);
headers.insert(AUTH_HEADER_KEY, api_key);
let client = reqwest::blocking::Client::builder()
.default_headers(headers)
.build()?;
Ok(client)
}