dingtalk-sdk 1.0.9

Dingtalk SDK for Rust.
Documentation
use url::Url;

use crate::error::{Error, Result};

pub(crate) fn normalize_base_url(value: impl AsRef<str>) -> Result<Url> {
    let raw = value.as_ref().trim();
    let mut url = Url::parse(raw).map_err(|source| Error::InvalidConfig {
        message: format!("Invalid base_url `{raw}`"),
        source: Some(Box::new(source)),
    })?;

    if url.cannot_be_a_base() {
        return Err(Error::InvalidConfig {
            message: "base_url must be hierarchical".to_string(),
            source: None,
        });
    }

    if url.query().is_some() || url.fragment().is_some() {
        return Err(Error::InvalidConfig {
            message: "base_url must not contain query or fragment".to_string(),
            source: None,
        });
    }

    if url.path() != "/" {
        let path = url.path().trim_end_matches('/').to_string();
        if path.is_empty() {
            url.set_path("/");
        } else {
            url.set_path(&path);
        }
    }

    Ok(url)
}

pub(crate) fn endpoint_url(base_url: &Url, segments: &[&str]) -> Result<Url> {
    let mut url = base_url.clone();
    {
        let mut path_segments = url.path_segments_mut().map_err(|_| Error::InvalidConfig {
            message: "base_url must be hierarchical".to_string(),
            source: None,
        })?;
        for segment in segments {
            path_segments.push(segment);
        }
    }
    Ok(url)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn endpoint_url_encodes_segments() {
        let base = normalize_base_url("https://example.com/api").expect("base");
        let url = endpoint_url(&base, &["users", "a/b"]).expect("url");
        assert_eq!(url.as_str(), "https://example.com/api/users/a%2Fb");
    }

    #[test]
    fn normalize_base_url_rejects_query() {
        let error = normalize_base_url("https://example.com/api?x=1").expect_err("must fail");
        match error {
            Error::InvalidConfig { .. } => {}
            other => panic!("unexpected error: {other:?}"),
        }
    }
}