clicksend-rs 0.1.1

Unofficial ClickSend SDK for Rust (async + optional blocking).
Documentation
//! Helpers for parsing inbound webhook payloads from ClickSend.
//!
//! ClickSend POSTs delivery receipts and inbound SMS messages to your
//! configured callback URLs. The body is JSON. These helpers decode it.

use crate::{
    errors::ClickSendError,
    types::{DeliveryReceiptWebhook, InboundSmsWebhook},
};

/// Decode an inbound SMS webhook JSON body. Returns
/// [`ClickSendError::Decode`] if the JSON is invalid.
pub fn parse_inbound_sms(body: &[u8]) -> Result<InboundSmsWebhook, ClickSendError> {
    serde_json::from_slice(body).map_err(|e| ClickSendError::Decode {
        message: e.to_string(),
        body: String::from_utf8_lossy(body).into_owned(),
    })
}

/// Decode an SMS delivery receipt webhook JSON body. Returns
/// [`ClickSendError::Decode`] if the JSON is invalid.
pub fn parse_delivery_receipt(body: &[u8]) -> Result<DeliveryReceiptWebhook, ClickSendError> {
    serde_json::from_slice(body).map_err(|e| ClickSendError::Decode {
        message: e.to_string(),
        body: String::from_utf8_lossy(body).into_owned(),
    })
}

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

    #[test]
    fn parses_inbound() {
        let body = br#"{"message_id":"abc","from":"+15551234567","to":"+15557654321","body":"hi","timestamp":1700000000,"originator":"clicksend"}"#;
        let parsed = parse_inbound_sms(body).unwrap();
        assert_eq!(parsed.message_id.as_deref(), Some("abc"));
        assert_eq!(parsed.from.as_deref(), Some("+15551234567"));
    }

    #[test]
    fn parses_receipt() {
        let body = br#"{"message_id":"abc","status":"DELIVERED","status_code":"201","timestamp":1700000000}"#;
        let parsed = parse_delivery_receipt(body).unwrap();
        assert_eq!(parsed.status.as_deref(), Some("DELIVERED"));
    }

    #[test]
    fn handles_missing_fields() {
        let parsed = parse_inbound_sms(b"{}").unwrap();
        assert!(parsed.message_id.is_none());
    }
}