babelforce-manager-sdk 0.43.0

Rust SDK for the babelforce manager APIs — auth, user & agent management, call reporting, metrics, and task automations.
Documentation
//! Raw-JSON reads for endpoints whose **generated models are stricter than the live API** (spec
//! drift: fields declared required/non-null that production returns as `null`). Consumers that
//! only re-serialize the payload (the ai-agents reporting datasource, its CSV export) read raw
//! and lose nothing — and never break on the next too-strict field.

use serde_json::Value;

use crate::error::ManagerError;
use crate::gen::manager::apis::configuration::Configuration;

/// A raw JSON GET with the same auth/user-agent the generated fns apply.
pub(crate) async fn get_json(
    cfg: &Configuration,
    path_and_query: &str,
) -> Result<Value, ManagerError> {
    let url = format!("{}{}", cfg.base_path, path_and_query);
    let mut req = cfg.client.get(&url);
    if let Some(ua) = &cfg.user_agent {
        req = req.header(reqwest::header::USER_AGENT, ua.clone());
    }
    if let Some(token) = &cfg.bearer_access_token {
        req = req.bearer_auth(token);
    } else if let Some(token) = &cfg.oauth_access_token {
        req = req.bearer_auth(token);
    }
    let resp = req
        .send()
        .await
        .map_err(|e| ManagerError::Network(e.to_string()))?;
    let status = resp.status().as_u16();
    let body = resp
        .text()
        .await
        .map_err(|e| ManagerError::Network(e.to_string()))?;
    if !(200..300).contains(&status) {
        return Err(ManagerError::from_response(status, body));
    }
    serde_json::from_str(&body).map_err(|e| ManagerError::Decode(e.to_string()))
}

/// A raw JSON body-less POST with the same auth/user-agent the generated fns apply — for action
/// endpoints (e.g. hangup) whose typed *response* models are stricter than the live API.
pub(crate) async fn post_json(
    cfg: &Configuration,
    path_and_query: &str,
) -> Result<Value, ManagerError> {
    send_raw(cfg, reqwest::Method::POST, path_and_query, None).await
}

/// A raw JSON POST carrying a JSON body — for write endpoints (e.g. application create) whose
/// typed *response* models cannot decode live success payloads: the POST succeeds server-side,
/// so a client-side decode failure would misreport a completed write as an error.
pub(crate) async fn post_json_body(
    cfg: &Configuration,
    path_and_query: &str,
    body: &Value,
) -> Result<Value, ManagerError> {
    send_raw(cfg, reqwest::Method::POST, path_and_query, Some(body)).await
}

/// A raw JSON PUT carrying a JSON body — the PUT sibling of [`post_json_body`], for update
/// endpoints (e.g. application update) with the same too-strict typed response models.
pub(crate) async fn put_json(
    cfg: &Configuration,
    path_and_query: &str,
    body: &Value,
) -> Result<Value, ManagerError> {
    send_raw(cfg, reqwest::Method::PUT, path_and_query, Some(body)).await
}

async fn send_raw(
    cfg: &Configuration,
    method: reqwest::Method,
    path_and_query: &str,
    body: Option<&Value>,
) -> Result<Value, ManagerError> {
    let url = format!("{}{}", cfg.base_path, path_and_query);
    let mut req = cfg.client.request(method, &url);
    if let Some(ua) = &cfg.user_agent {
        req = req.header(reqwest::header::USER_AGENT, ua.clone());
    }
    if let Some(token) = &cfg.bearer_access_token {
        req = req.bearer_auth(token);
    } else if let Some(token) = &cfg.oauth_access_token {
        req = req.bearer_auth(token);
    }
    if let Some(b) = body {
        req = req.json(b);
    }
    let resp = req
        .send()
        .await
        .map_err(|e| ManagerError::Network(e.to_string()))?;
    let status = resp.status().as_u16();
    let body = resp
        .text()
        .await
        .map_err(|e| ManagerError::Network(e.to_string()))?;
    if !(200..300).contains(&status) {
        return Err(ManagerError::from_response(status, body));
    }
    serde_json::from_str(&body).map_err(|e| ManagerError::Decode(e.to_string()))
}

/// Split a paginated v2 envelope into `(items, pages, current, total)`.
pub(crate) fn page_parts(v: Value, default_page: i32) -> (Vec<Value>, i32, i32, Option<i32>) {
    let items = v
        .get("items")
        .and_then(Value::as_array)
        .cloned()
        .unwrap_or_default();
    let p = v.get("pagination").cloned().unwrap_or(Value::Null);
    let num = |k: &str| p.get(k).and_then(Value::as_i64).map(|n| n as i32);
    (
        items,
        num("pages").unwrap_or(1),
        num("current").unwrap_or(default_page),
        num("total"),
    )
}