use reqwest::{ Client, Response, Method, RequestBuilder };
use tracing::info;
use serde::{ Serialize, Deserialize };
use anyhow::{ Result, anyhow };
use serde_json::Value;
use crate::{ NameCheapClient, NAMECHEAP_API_URL, NAMECHEAP_SANDBOX_API_URL };
use crate::utils::xml_parser::parse_xml_to_json;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
#[derive(PartialEq, Eq, Hash)]
pub struct Request {
client: NameCheapClient,
command: String,
page: Option<i64>,
domain_name: Option<String>,
domain_id: Option<i64>,
params: Option<Value>,
}
impl Request {
pub fn new(
client: NameCheapClient,
command: String,
page: Option<i64>,
domain_name: Option<String>,
params: Option<Value>,
) -> Self {
Request {
client,
command,
page,
domain_name,
params,
domain_id: None,
}
}
pub fn build_url(&self) -> String {
let base_url = if self.client.production {
NAMECHEAP_API_URL
} else {
NAMECHEAP_SANDBOX_API_URL
};
let mut url = format!(
"{}/xml.response?ApiUser={}&ApiKey={}&UserName={}&Command={}&ClientIp={}",
base_url,
self.client.api_user,
self.client.api_key,
self.client.user_name,
self.command,
self.client.client_ip
);
if let Some(page) = self.page {
url.push_str(&format!("&Page={}", page));
}
if let Some(ref domain_name) = self.domain_name {
url.push_str(&format!("&DomainName={}", domain_name));
}
if let Some(domain_id) = self.domain_id {
url.push_str(&format!("&DomainID={}", domain_id));
}
if let Some(ref params) = self.params {
if let Some(sld) = params.get("SLD") {
url.push_str(&format!("&SLD={}", sld.as_str().unwrap_or("")));
}
if let Some(tld) = params.get("TLD") {
url.push_str(&format!("&TLD={}", tld.as_str().unwrap_or("")));
}
}
url
}
pub async fn send(&self) -> Result<Value> {
let url: String = self.build_url();
info!("Sending request to URL: {:#?}", url);
let client: Client = Client::new();
let request: RequestBuilder = client
.request(Method::GET, &url)
.header("Accept", "application/xml")
.header("Content-Type", "application/xml");
let response: Response = request.send().await?;
if let Some(content_type) = response.headers().get("Content-Type") {
if !content_type.to_str().unwrap_or("").contains("xml") {
return Err(anyhow!("Response is not XML"));
}
}
let response_text: String = response.text().await?;
let json_value: Value = parse_xml_to_json(&response_text)?;
Ok(json_value)
}
pub fn with_domain_name(mut self, domain_name: String) -> Self {
self.domain_name = Some(domain_name);
self
}
pub fn with_domain_id(mut self, domain_id: i64) -> Self {
self.domain_id = Some(domain_id);
self
}
}