hetzner 1.0.0

A Rust library for managing DNS records and zones on Hetzner's platform, providing tools for networking and DNS management.
Documentation
use super::enums::{ServerSort, ServerStatus};
use crate::HetznerClient;
use crate::error::Result;
use crate::types::{CloudServer, CloudServerEnvelope, CloudServersEnvelope, CreateServerResponse};
use reqwest::Method;
use serde::Serialize;

#[derive(Debug, Clone, Default)]
pub struct ListServersParams {
    pub name: Option<String>,
    pub label_selector: Option<String>,
    pub sort: Vec<ServerSort>,
    pub status: Vec<ServerStatus>,
    pub page: Option<u32>,
    pub per_page: Option<u32>,
}

impl ListServersParams {
    fn to_query_pairs(&self) -> Vec<(String, String)> {
        let mut query = Vec::new();

        if let Some(name) = &self.name {
            query.push(("name".to_string(), name.clone()));
        }

        if let Some(label_selector) = &self.label_selector {
            query.push(("label_selector".to_string(), label_selector.clone()));
        }

        for sort in &self.sort {
            query.push(("sort".to_string(), sort.as_str().to_string()));
        }

        for status in &self.status {
            query.push(("status".to_string(), status.as_str().to_string()));
        }

        if let Some(page) = self.page {
            query.push(("page".to_string(), page.to_string()));
        }

        if let Some(per_page) = self.per_page {
            query.push(("per_page".to_string(), per_page.to_string()));
        }

        query
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct CreateServerInput {
    pub name: String,
    pub server_type: String,
    pub image: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub location: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub start_after_create: Option<bool>,
}

#[derive(Debug, Clone, Copy)]
pub struct ServersApi<'a> {
    pub(crate) client: &'a HetznerClient,
}

impl<'a> ServersApi<'a> {
    pub async fn list(self, params: Option<&ListServersParams>) -> Result<Vec<CloudServer>> {
        let query = params.map(ListServersParams::to_query_pairs);

        let response: CloudServersEnvelope = self
            .client
            .request_cloud(Method::GET, "servers", query.as_ref(), None)
            .await?;

        Ok(response.servers)
    }

    pub async fn get(self, server_id: u64) -> Result<CloudServerEnvelope> {
        let path = format!("servers/{server_id}");
        self.client
            .request_cloud(Method::GET, &path, None::<&()>, None)
            .await
    }

    pub async fn create(self, input: &CreateServerInput) -> Result<CreateServerResponse> {
        self.client
            .request_cloud(
                Method::POST,
                "servers",
                None::<&()>,
                Some(serde_json::to_value(input)?),
            )
            .await
    }
}