Skip to main content

dna_rs/ops/
availability.rs

1use serde_json::Value;
2
3use crate::client::DnaClient;
4use crate::error::{DnaError, DnaResult};
5use crate::models::domain::{AvailabilityResult, BulkSearchItem, BulkSearchQuery};
6
7impl DnaClient {
8    /// Check availability of all `domain × extension` combinations.
9    ///
10    /// `command` is forwarded verbatim (e.g. `"create"`, `"transfer"`).
11    pub async fn check_availability(
12        &self,
13        domains: &[&str],
14        extensions: &[&str],
15        period: u32,
16        command: &str,
17    ) -> DnaResult<Vec<AvailabilityResult>> {
18        let queries: Vec<BulkSearchQuery> = domains
19            .iter()
20            .flat_map(|d| {
21                extensions.iter().map(move |ext| BulkSearchQuery {
22                    domain_name: format!("{}.{}", d, ext.trim_start_matches('.')),
23                })
24            })
25            .collect();
26
27        if queries.is_empty() {
28            return Err(DnaError::InvalidArgument("No domain names provided".into()));
29        }
30
31        let raw: Value = self.http.post("domains/bulk-search", &queries).await?;
32
33        let items: Vec<BulkSearchItem> =
34            if let Some(arr) = raw.get("infos").and_then(Value::as_array) {
35                serde_json::from_value(Value::Array(arr.clone()))?
36            } else if raw.is_array() {
37                serde_json::from_value(raw)?
38            } else {
39                return Err(DnaError::UnexpectedResponse(
40                    "Unexpected bulk-search response shape".into(),
41                ));
42            };
43
44        let results = items
45            .into_iter()
46            .map(|item| {
47                let domain_raw = item.domain_name.unwrap_or_default();
48                let tld = item.tld.unwrap_or_else(|| {
49                    domain_raw
50                        .splitn(2, '.')
51                        .nth(1)
52                        .unwrap_or("")
53                        .to_lowercase()
54                });
55                let domain_name = domain_raw
56                    .to_lowercase()
57                    .strip_suffix(&format!(".{}", tld))
58                    .unwrap_or(domain_raw.to_lowercase().as_str())
59                    .to_owned();
60
61                let status_raw = item.status.unwrap_or_default().to_lowercase();
62                let is_available = matches!(status_raw.as_str(), "available" | "1" | "true");
63
64                AvailabilityResult {
65                    tld,
66                    domain_name,
67                    status: if is_available {
68                        "available".into()
69                    } else {
70                        "notavailable".into()
71                    },
72                    command: command.to_owned(),
73                    period: item.period.unwrap_or(period),
74                    is_fee: item.is_premium.unwrap_or(false),
75                    price: item.price,
76                    currency: item.currency,
77                    reason: item.reason,
78                }
79            })
80            .collect();
81
82        Ok(results)
83    }
84}