github-mcp 0.1.3

GitHub v3 REST API MCP server, generated by mcpify.
Documentation
// GitHub v3 REST API MCP server — generated by mcpify. Do not hand-edit.

use url::Url;

/// Joins a configured base URL with an operation path and query params,
/// normalizing slashes so callers never have to think about
/// trailing/leading separators.
pub fn build_api_url(
    base_url: &str,
    path: &str,
    query: &[(String, String)],
) -> anyhow::Result<String> {
    let base = if base_url.ends_with('/') {
        base_url.to_string()
    } else {
        format!("{base_url}/")
    };
    let base = Url::parse(&base)?;
    let mut url = base.join(path.trim_start_matches('/'))?;

    // `query_pairs_mut()` unconditionally leaves a trailing `?` behind even
    // when zero pairs are appended to it, so it's only touched when there's
    // actually something to add.
    if !query.is_empty() {
        let mut pairs = url.query_pairs_mut();
        for (key, value) in query {
            pairs.append_pair(key, value);
        }
    }

    Ok(url.to_string())
}

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

    #[test]
    fn joins_a_base_url_and_path_without_double_slashes() {
        let url = build_api_url("https://api.example.com", "/widgets", &[]).unwrap();
        assert_eq!(url, "https://api.example.com/widgets");
    }

    #[test]
    fn handles_a_base_url_without_a_trailing_slash() {
        let url = build_api_url("https://api.example.com/v1", "widgets", &[]).unwrap();
        assert_eq!(url, "https://api.example.com/v1/widgets");
    }

    #[test]
    fn appends_query_parameters() {
        let url = build_api_url(
            "https://api.example.com",
            "/widgets",
            &[("limit".to_string(), "10".to_string())],
        )
        .unwrap();
        assert_eq!(url, "https://api.example.com/widgets?limit=10");
    }
}